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

我看到很多关于如何使用sed,awk或gawk进行search和replace的示例和手册页。

但就我而言,我有一个正则expression式,我想运行一个文本文件来提取一个特定的值。 我不想做search和replace。 这是从bash调用。 我们用一个例子:

示例正则expression式:

.*abc([0-9]+)xyz.* 

input文件示例:

 a b c abc12345xyz a b c 

这听起来很简单,我不知道如何正确调用sed / awk / gawk。 我希望做的是从我的bash脚本里面得到:

 myvalue=$( sed <...something...> input.txt ) 

我尝试过的东西包括:

 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 

我的sed (Mac OS X)没有使用+ 。 我尝试*而不是我添加p标签打印匹配:

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

至less匹配一个没有+数字字符,我会使用:

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

你可以使用sed来做到这一点

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

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

 rip 'abc(\d+)xyz' '$1' 

我使用perl来使自己更容易。 例如

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

这运行Perl, -n选项指示Perl从STDIN一次读入一行,然后执行代码。 -e选项指定要运行的指令。

该指令在读取的行上运行一个正则expression式,如果匹配则打印出第一套大括号( $1 )的内容。

你可以做到这一点将多个文件名也结束。 例如

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

如果你的grep版本支持它,你可以使用-o选项来打印与你的正则expression式匹配的任何行的部分。

如果不是那么这是我能想出的最好的sed

 sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//' 

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

有这样的问题:

 sed -e 's/.*\([0-9]*\).*/&/' 

…. 要么

 sed -e 's/.*\([0-9]*\).*/\1/' 

…是sed只支持“贪婪”匹配…所以第一个*将匹配其余的行。 除非我们可以使用否定的字符类来实现非贪婪匹配…或者与Perl兼容或其它正则expression式的其他扩展的sed版本,否则我们不能从模式空间中提取精确的模式匹配(a线)。

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

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

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


使用grep你可以使用后台和前瞻:

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

当它出现在abcxyz时,它检查pattern [0-9]+ ,只是打印数字。

perl是最干净的语法,但如果你没有perl(并不总是在那里,我明白),那么使用gawk和正则expression式的组件的唯一方法是使用gensubfunction。

 gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file 

样本input文件的输出将会是

 12345 

注意:gensubreplace整个正则expression式(在//之间),所以你需要在([0-9] +)之前和之后放置。*以replace前后的文本。

如果你想select线条,然后去掉你不想要的位:

 egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//' 

它基本上使用egrepselect你想要的行,然后使用sed egrep数字前后的位。

你可以在这里看到这个:

 pax> echo 'a b c abc12345xyz a b c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//' 12345 pax> 

更新:显然如果你的实际情况比较复杂的话,RE需要我修改。 例如,如果您始终将一个数字埋在零个或多个非数字开始和结尾:

 egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//' 

你可以用shell来做

 while read -r line do case "$line" in *abc*[0-9]*xyz* ) t="${line##abc}" echo "num is ${t%%xyz}";; esac done <"file" 

对于awk。 我会使用下面的脚本:

 /.*abc([0-9]+)xyz.*/ { print $0; next; } { /* default, do nothing */ } 
 gawk '/.*abc([0-9]+)xyz.*/' file