如何使用sed,awk或gawk只打印匹配的内容?

Sté*_*ane 97 regex unix awk sed gawk

我看到很多关于如何使用sed,awk或gawk进行搜索和替换等操作的示例和手册页.

但在我的情况下,我有一个正则表达式,我想对文本文件运行以提取特定的值.我不想做搜索和替换.这是从bash调用的.我们来举个例子:

正则表达式示例:

.*abc([0-9]+)xyz.*
Run Code Online (Sandbox Code Playgroud)

示例输入文件:

a
b
c
abc12345xyz
a
b
c
Run Code Online (Sandbox Code Playgroud)

听起来很简单,我无法弄清楚如何正确调用sed/awk/gawk.我希望做的是,在我的bash脚本中有:

myvalue=$( sed <...something...> input.txt )
Run Code Online (Sandbox Code Playgroud)

我尝试过的事情包括:

sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing
Run Code Online (Sandbox Code Playgroud)

mou*_*iel 42

我的sed(Mac OS X)无法使用+.我尝试了*,我添加了p用于打印匹配的标签:

sed -n 's/^.*abc\([0-9]*\)xyz.*$/\1/p' example.txt
Run Code Online (Sandbox Code Playgroud)

为了匹配至少一个数字字符+,我会使用:

sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$/\1/p' example.txt
Run Code Online (Sandbox Code Playgroud)

  • 那是因为你没有使用现代RE格式,因此+是一个标准字符,你应该用{,}语法表达.您可以添加use -E sed选项以触发现代RE格式.检查re_format(7),特别是描述的最后一段http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man7/re_format.7.html (3认同)
  • ...以及打印匹配的"p"选项,我也不知道.再次感谢. (2认同)
  • 我不得不逃避`+`然后它对我有效:`sed -n's /^.*abc \([0-9]\+ \)xyz.*$ /\1/p'` (2认同)

Ili*_*oly 32

您可以使用sed来执行此操作

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
Run Code Online (Sandbox Code Playgroud)
  • -n 不打印生成的行
  • -r这使得你没有逃脱捕获组的parens ().
  • \1 捕获组匹配
  • /g 全球比赛
  • /p 打印结果

我为自己写了一个工具,使这更容易

rip 'abc(\d+)xyz' '$1'
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止,这是迄今为止最好,最好解释的答案! (2认同)

PP.*_*PP. 17

我用它perl来让自己更容易.例如

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'
Run Code Online (Sandbox Code Playgroud)

这运行Perl,该-n选项指示Perl一次从STDIN读取一行并执行代码.该-e选项指定要运行的指令.

该指令在读取行上运行正则表达式,如果匹配则打印出第一组bracks($1)的内容.

你可以这样做,最后也会有多个文件名.例如

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt


Jim*_*nis 5

如果您的版本grep支持它,您可以使用该-o选项打印与您的正则表达式匹配的任何行的部分.

如果没有,那么这是sed我能想到的最好的:

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'
Run Code Online (Sandbox Code Playgroud)

...删除/跳过没有数字,对于其余行,删除所有前导和尾随非数字字符.(我只是猜测你的意图是从包含一行的每一行中提取数字).

这样的问题:

sed -e 's/.*\([0-9]*\).*/&/' 
Run Code Online (Sandbox Code Playgroud)

.... 要么

sed -e 's/.*\([0-9]*\).*/\1/'
Run Code Online (Sandbox Code Playgroud)

...... sed只支持"贪婪"匹配...所以第一个.*将与该行的其余部分匹配.除非我们可以使用否定的字符类来实现非贪婪的匹配...或者sed与其正则表达式兼容或其他扩展的版本,我们无法从模式空间中提取精确的模式匹配(一行).


fed*_*qui 5

您可以使用awkwithmatch()来访问捕获的组:

$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345
Run Code Online (Sandbox Code Playgroud)

这试图匹配模式abc[0-9]+xyz。如果这样做,它将把它的切片存储在数组中matches,数组的第一项是块[0-9]+。由于match() 返回该子字符串开始位置的字符位置或索引(1,如果它从字符串的开头开始),因此它会触发该print操作。


您可以使用grep后视和前视:

$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345
Run Code Online (Sandbox Code Playgroud)

[0-9]+当模式出现在abc和中时,这会检查模式xyz并仅打印数字。