代码之家  ›  专栏  ›  技术社区  ›  Pablo

如何使用sed只输出捕获的组?

  •  228
  • Pablo  · 技术社区  · 15 年前

    有什么办法可以说 sed 只输出捕获的组?例如,给定输入:

    This is a sample 123 text and some 987 numbers
    

    和图案:

    /([\d]+)/
    

    我可以只得到123和987输出的方式由反向引用格式化?

    8 回复  |  直到 7 年前
        1
  •  253
  •   Dennis Williamson    7 年前

    要让它起作用的关键是 sed 排除您不想输出的内容,并指定您想要的内容。

    string='This is a sample 123 text and some 987 numbers'
    echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
    

    上面写着:

    • 不默认打印每行( -n )
    • 排除零个或多个非数字
    • 包含一个或多个数字
    • 排除一个或多个非数字
    • 包含一个或多个数字
    • 排除零个或多个非数字
    • 打印替换( p )

    一般来说,在 塞德 使用圆括号捕获组,并使用反向引用输出捕获的内容:

    echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
    

    将输出“bar”。如果你使用 -r ( -E 对于os x)对于扩展regex,不需要转义括号:

    echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
    

    最多可以有9个捕获组及其备份引用。后面的引用按组出现的顺序编号,但它们可以按任何顺序使用,并且可以重复:

    echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
    

    输出“A bar A”。

    如果你有GNU grep (它也可以在bsd中工作,包括os x):

    echo "$string" | grep -Po '\d+'
    

    或变更,如:

    echo "$string" | grep -Po '(?<=\D )(\d+)'
    

    这个 -P 选项启用Perl兼容的正则表达式。见 man 3 pcrepattern man 3 pcresyntax

        2
  •  49
  •   Peter McG    15 年前

    sed最多有九个记住的模式,但您需要使用转义括号来记住正则表达式的某些部分。

    here 示例和更多细节

        3
  •  28
  •   ghostdog74    15 年前

    你可以用grep

    grep -Eow "[0-9]+" file
    
        4
  •  7
  •   Joseph Quinsey Taseen    15 年前

    我相信这个问题中给出的模式只是以身作则,目的是为了配合 任何 模式。

    如果你有 塞德 由于gnu扩展允许在模式空间中插入换行符,一个建议是:

    > set string = "This is a sample 123 text and some 987 numbers"
    >
    > set pattern = "[0-9][0-9]*"
    > echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
    123
    987
    > set pattern = "[a-z][a-z]*"
    > echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
    his
    is
    a
    sample
    text
    and
    some
    numbers
    

    这些例子是关于tcsh的(是的,我 知道 它是错误的外壳)与Cygwin。(编辑:对于bash,删除set,并删除其周围的空格=。)

        5
  •  6
  •   Ciro Santilli OurBigBook.com    8 年前

    放弃并使用perl

    自从 sed 不需要削减它,让我们放弃使用perl,至少它是 LSB 虽然 grep GNU扩展不是:-)

    • 打印整个匹配部分,不需要匹配组或查找:

      cat <<EOS | perl -lane 'print m/\d+/g'
      a1 b2
      a34 b56
      EOS
      

      输出:

      12
      3456
      
    • 每行一个匹配,通常是结构化数据字段:

      cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
      a1 b2
      a34 b56
      EOS
      

      输出:

      1
      34
      

      带后视镜:

      cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
      a1 b2
      a34 b56
      EOS
      
    • 多个字段:

      cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
      a1 c0 b2 c0
      a34 c0 b56 c0
      EOS
      

      输出:

      1 2
      34 56
      
    • 每行有多个匹配项,通常是非结构化数据:

      cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
      a1 b2
      a34 b56 a78 b90
      EOS
      

      输出:

      1 
      34 78
      

      带后视镜:

      cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
      a1 b2
      a34 b56 a78 b90
      EOS
      

      输出:

      1
      3478
      
        6
  •  6
  •   IsaaC    8 年前

    数字序列

    这个答案适用于任何数量的数字组。例子:

    $ echo 'Num123that456are7899900contained0018166intext' |
    > sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
    123 456 7899900 0018166
    

    扩大回答。

    有什么方法可以告诉sed只输出捕获的组吗?

    对.用捕获组替换所有文本:

    $ echo 'Number 123 inside text' | sed 's/[^0-9]*\([0-9]\{1,\}\)[^0-9]*/\1/'
    123
    
    s/[^0-9]*                           # several non-digits
             \([0-9]\{1,\}\)            # followed by one or more digits
                            [^0-9]*     # and followed by more non-digits.
                                   /\1/ # gets replaced only by the digits.
    

    或使用扩展语法(减少反引号并允许使用+):

    $ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
    123
    

    要避免在没有号码时打印原始文本,请使用:

    $ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
    
    • (-n)默认情况下不打印输入。
    • (/P)仅在完成替换时打印。

    要匹配多个数字(并打印它们):

    $ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
    123 456
    

    适用于任何数字运行计数:

    $ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
    $ echo "$str" | sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
    123 456 7899900 0018166
    

    与grep命令非常相似:

    $ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
    $ echo "$str" | grep -Po '\d+'
    123
    456
    7899900
    0018166
    

    关于\d

    和图案: /([\d]+)/

    sed无法识别'\d'(快捷方式)语法。上面使用的ascii等价物 [0-9] 不完全等同。唯一的替代解决方案是使用字符类:'[[:digit:]`。

    所选答案使用这样的“字符类”来构建解决方案:

    $ str='This is a sample 123 text and some 987 numbers'
    $ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
    

    这个解决方案只适用于(确切地说)两组数字。

    当然,由于答案是在shell内部执行的,我们可以定义两个变量来缩短这样的答案:

    $ str='This is a sample 123 text and some 987 numbers'
    $ d=[[:digit:]]     D=[^[:digit:]]
    $ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*/\1 \2/p"
    

    但是,正如已经解释过的,使用 s/…/…/gp 命令更好:

    $ str='This is 75577 a sam33ple 123 text and some 987 numbers'
    $ d=[[:digit:]]     D=[^[:digit:]]
    $ echo "$str" | sed -rn "s/$D*($d+)$D*/\1 /gp"
    75577 33 123 987
    

    这将包括重复运行的数字和编写一个简短的(er)命令。

        7
  •  5
  •   Bert F    15 年前

    尝试

    sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
    

    我在cygwin手下得到这个:

    $ (echo "asdf"; \
       echo "1234"; \
       echo "asdf1234adsf1234asdf"; \
       echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
      sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
    
    1234
    1234 1234
    1 2 3 4 5 6 7 8 9
    $
    
        8
  •  2
  •   Thomas Bratt    11 年前

    这不是OP要求的(捕获组),但您可以使用以下方法提取数字:

    S='This is a sample 123 text and some 987 numbers'
    echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
    

    给出以下信息:

    123
    987