如何仅使用sed输出捕获的组

有什么办法可以告诉sed只输出捕获的组? 例如给出的input:

 This is a sample 123 text and some 987 numbers 

和模式:

 /([\d]+)/ 

我可以得到只有123和987输出格式的回引用?

让这个工作的关键是告诉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

如果你有GNU grep (它也可能在BSD中工作,包括OS X):

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

或变体,如:

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

-P选项启用Perl兼容正则expression式。 见man 3 pcrepatternman 3 pcresyntax

Sed最多有9个记忆模式,但是您需要使用转义括号来记住正则expression式的部分。

看到这里的例子和更多的细节

你可以使用grep

 grep -Eow "[0-9]+" file 

我相信问题中提出的模式只是举例,目标是匹配任何模式。

如果你有一个允许在模式空间插入换行符的GNU扩展的sed ,一个build议是:

 > 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 = "[az][az]*" > echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p" his is a sample text and some numbers 

这些例子是与CYCWIN tcsh(是的,我知道它的错误壳)。 (编辑:对于bash,删除设置,以及周围的空格=。)

尝试

 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 $ 

放弃并使用Perl

由于sed不会削减它,所以我们只是扔毛巾和使用Perl,至less它是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 

数字的运行

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

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

扩大答案。

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

是。 将所有文本replace为捕获组:

 $ 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. 

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

 $ 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)默认情况下不要打印input。
  • (/ 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'(快捷键)语法。 上面[0-9]使用的ascii等价物并不完全等价。 唯一的select是使用一个字符类:'[[:digit:]]`。

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

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

该解决scheme只适用于(完全)两个数字运行。

当然,在shell中执行答案时,我们可以定义一些variables来缩短这个答案:

 $ 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)命令。

这不是什么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