如何使用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线)。
您可以使用awk
和match()
来访问捕获的组:
$ 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
当它出现在abc
和xyz
时,它检查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.*$//'
它基本上使用egrep
select你想要的行,然后使用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