有没有一种方法告诉sed只输出捕获的组?
例如,给定输入:
This is a sample 123 text and some 987 numbers
和模式:
/([\d]+)/
我能得到只有123和987输出的方式格式化后引用?
有没有一种方法告诉sed只输出捕获的组?
例如,给定输入:
This is a sample 123 text and some 987 numbers
和模式:
/([\d]+)/
我能得到只有123和987输出的方式格式化后引用?
当前回答
Sed最多可以记住9个模式,但是您需要使用转义括号来记住正则表达式的部分内容。
请看这里的例子和更多细节
其他回答
我相信问题中给出的模式只是举例,目标是匹配任何模式。
如果你有一个允许在模式空间中插入换行符的GNU扩展sed,一个建议是:
> 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(是的,我知道它是错误的shell)和CYGWIN。(编辑:对于bash,删除set和=周围的空格。)
这不是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
您需要包含整行来打印组,这是您在第二个命令中所做的,但您不需要对第一个通配符进行分组。这也可以:
echo "/home/me/myfile-99" | sed -r 's/.*myfile-(.*)$/\1/'
运行(s)位数
这个答案适用于任何计数的数字组。例子:
$ 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
pattern: /([\d]+)/
Sed不识别'\d'(快捷键)语法。上面[0-9]使用的等价ascii并不是完全等价的。唯一的替代解决方案是使用字符类:'[[: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)命令。
您可以使用ripgrep,它似乎也是简单替换的sed替代品,就像这样
rg '(\d+)' -or '$1'
由于两次匹配,ripgrep使用-o或——only matching和-r或——replace两次只输出$1的第一个捕获组(引用以避免shell将其解释为变量)。