【问题标题】:sed: filter string subset from lines matching regexpsed:从匹配正则表达式的行中过滤字符串子集
【发布时间】:2020-07-14 16:09:27
【问题描述】:

我有一个格式如下的文件:

abc: A B C D E
abc: 1 2 3 4 5 
def  D E F G H
def: 10 11 12 23 99
...

这是第一行字符串,':'之后是下一行数字的标题。我想使用sed 仅提取以PATTERN 开头的行,其中包含数字。

一行中的数字数量是可变的,但假设我确切知道我期待多少,所以我尝试了这个命令:

% sed 's/^abc: \([0-9]+ [0-9]+ [0-9]+\)$/\1/g' < file.txt

但它会转储文件中的所有条目。我做错了什么?

【问题讨论】:

    标签: linux bash macos sed scripting


    【解决方案1】:
    1. sed 进行替换并打印每一行,无论是否发生替换。

    2. 您的正则表达式错误。如果给出扩展正则表达式标志 (-E),它将仅匹配由空格分隔的三个数字。没有它,甚至没有,因为+ 符号将按字面意思解释。

    3. 这里最好使用地址并且只打印匹配的行:

    sed -nE '/^abc: [0-9]+ [0-9]+ [0-9]+ [0-9]+ [0-9]+$/p' < file.txt
    

    或更好,

    sed -nE '/^abc:( [0-9]+){5}$/p' < file.txt
    

    -n 标志禁用 (1) 中描述的sed 的“打印所有行”行为。只会打印到达p 命令的行。

    【讨论】:

    • 感谢您的评论。 sed -nE '/^abc: ([0-9]+ ){5}$/p' &lt; file.txt 仅在行中的最后一个数字也以空格字符结尾时才有效?
    • 我把空格放在数字的前面,假设:后面和数字之间总是有一个空格:sed -En '/abc:( [0-9]+)+/p' file.txt(你不需要@ 987654332@ 重定向,如果给定文件名,sed 从文件中读取)
    • @Mark True,我已经更正了,但现在如果最后一个数字后面有空格,它将不匹配。您可以根据您的需要调整该正则表达式。特别是,如果您想允许额外的空格和制表符,请考虑在$ 之前添加[ \t]*
    • @StephenP 是的,&lt; 在这里是一次性的。使用&lt;,shell 打开文件,没有它sed 也可以。
    • @Quasímodo,@Stephen P,感谢您的 cmets,它现在可以工作了。如果我只想提取匹配的数字(并删除前缀,例如 abc),以下命令对您来说是否合适? sed -n 's/^abc: \([0-9].*\)/\1/p'
    【解决方案2】:

    只提取以PATTERN字符串开头的一行,行中带有数字一行中的数字是可变的表示至少有一个数字,所以: p>

    $ sed -n '/abc: \([0-9]\+\)/p' file
    

    输出:

    abc: 1 2 3 4 5 
    

    正好有 5 个数字,使用:

    $ sed -n '/abc: \([0-9]\+\( \|$\)\)\{5\}/p' file
    

    【讨论】:

    • 奇怪的是,你的两种模式在 macOS 上不适合我,虽然他们应该 - 但他们确实在 linux 上工作,并且如果我添加 -E 并删除 `\`es,它们可以在 macOS 上运行
    • 是的,GNU rot .
    【解决方案3】:

    @Mark 在评论中的附加问题 “如果我只想提取匹配的数字(并删除前缀,例如 abc)......” 这是我想出的模式: p>

    sed -En 's/^abc: (([0-9]+[ \t]?)+)[ \t]*$/\1/gp' file.txt
    

    我将-E 标志用于扩展正则表达式以避免所有需要的转义。
    鉴于此文件:

    abc: A B C D E
    abc: 1 2 3 4 5 
    abc: 1 c9 A 7f
    def  D E F G H
    def: 10 11 12 23 99
    

    …这个正则表达式匹配abc: 1 2 3 4 5,但不包括abc: 1 c9 A 7f——它还允许可变空格和尾随空格。

    【讨论】:

    • 谢谢,它对我有用。不过还有一件事:事实证明我的行中可能有负数,所以我像这样更新了你的表达式:sed -En 's/^abc: (([-]?[0-9]+[ \t]?)+)[ \t]*$/\1/gp'
    • 顺便说一句,我试图删除“-E”参数并转义所有括号,但这对我不起作用。它只是没有返回任何东西。我在 ubuntu 上使用 GNU sed- 4.2.2。
    • @Mark 没有-E 你还必须转义加号“一个或多个”\+,而且我很确定,问号“可选”\?(但目前无法尝试)
    【解决方案4】:

    使用任何 sed:

    $ sed -n 's/^abc: \([0-9 ]*\)$/\1/p' file
    1 2 3 4 5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-14
      • 2011-11-08
      • 2013-01-23
      • 1970-01-01
      • 1970-01-01
      • 2022-07-11
      • 2013-03-02
      • 1970-01-01
      相关资源
      最近更新 更多