如果我有一个awk命令
pattern { ... }
如果模式使用了一个捕获组,我该如何在代码块中访问被捕获的字符串?
使用gawk,你可以使用match
函数来捕获带括号的组。
gawk 'match($0, pattern, ary) {print ary[1]}'
例子:echo "abcdef" | gawk 'match($0, /b(.*)e/, a) {print a[1]}'
输出cd
。
请注意使用的gawk实现了相关功能。
如果需要可移植的替代方案,您可以使用match()
和substr
来实现类似的结果。
示例:
echo "abcdef" | awk 'match($0, /b[^e]*/) {print substr($0, RSTART+1, RLENGTH-1)}'
输出 cd
命令。
这是一次追溯回忆的经历...
我很久以前就用 Perl 替代了 awk。
显然 AWK 正则表达式引擎无法捕获其组。
你可以考虑使用类似于:
perl -n -e'/test(\d+)/ && print $1'
-n标志使得Perl像awk一样循环遍历每一行。
我经常需要这个东西,所以我创建了一个基于 glenn jackman 答案的 bash 函数。
将此添加到您的 .bash_profile 等文件中。
function regex { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'0'}']}'; }
在文件中为每行捕获正则表达式
$ cat filename | regex '.*'
捕获文件中每一行的第一个正则表达式捕获组。
$ cat filename | regex '(.*)' 1
grep -o
有何不同? - bfontainegrep -o
输出捕获组? - Olle Härstedtgrep -o
会变得很丑陋。 - bfontaine你可以使用GNU awk:
$ cat hta
RewriteCond %{HTTP_HOST} !^www\.mysite\.net$
RewriteRule (.*) http://www.mysite.net/$1 [R=301,L]
$ gawk 'match($0, /.*(http.*?)\$/, m) { print m[1]; }' < hta
http://www.mysite.net/
RewriteRule (.*) http://www.mysite.net/$
,这比子组更多。 - rampionRSTART
和RLENGTH
指的是模式匹配到的子字符串。 - rampionhttp...
模式的整行。 - KFL.*?
,这是PCRE的一种语法,而在ERE中是未定义行为。我会删除我的评论。 - Ed Morton注意:使用gensub
不符合POSIX标准。
在没有扩展的情况下,您也可以在vanilla awk中模拟捕获。虽然这不是很直观:
步骤1. 使用gensub将匹配项用某个在字符串中不存在的字符括起来。 步骤2. 对该字符使用split。 步骤3. 分割后数组中每隔一个元素就是一个捕获组。
$ echo 'ab cb ad' | awk '{ split(gensub(/a./,SUBSEP"&"SUBSEP,"g",$0),cap,SUBSEP); print cap[2]"|" cap[4] ; }' ab|ad
gensub
是gawk
特有的函数。如果您在awk中输入awk --version
,那么您会得到什么呢?祝大家好运。 - shellterecho 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
- dubiousjimgawk --posix '{gensub(...)}'
吗? - dubiousjimgensub
函数的说法是错误的,但你的例子只适用于非常有限的情况:整个模式被分组,无法匹配像所有key=(value)
这样的内容,当我只想提取value
部分时。 - Meow我为了封装Peter Tillemans的答案而努力了一些时间,但是这是我想出来的:
function regex { perl -n -e "/$1/ && printf \"%s\n\", "'$1' }
我发现,与opsb基于awk的bash函数相比,这个针对以下正则表达式参数的函数工作得更好,因为我不想打印出“ms”。
'([0-9]*)ms$'
$1
的双引号/单引号标记。 - Demis'([0-9]*)ms$'
- 这是作为参数提供的吗(而字符串是另一个参数)?然后,perl -e
的输出被插入到bash的printf
命令中,以替换%s
,是这样吗?谢谢,我希望能够使用它。 - Demis我认为gawk的match()-to-array仅适用于捕获组的第一个实例。
如果有多个要捕获并执行任何复杂操作的内容,也许可以考虑使用其他方法。
gawk 'BEGIN { S = SUBSEP
} {
nx=split(gensub(/(..(..)..(..))/,
"\\1"(S)"\\2"(S)"\\3", "g", str),
arr, S)
for(x in nx) { perform-ops-over arr[x] } }'
这样做可以避免受到 gensub()
的限制,该函数会限制您的修改复杂度,或者受到 match()
的限制。
通过纯试错,我注意到 gawk 在 Unicode 模式下有一个警告:对于一个有效的 Unicode 字符串뀇꿬,其包含以下 6 个八进制代码:
情况 1:匹配单个字节没有问题,但它也会报告 RSTART 的多字节值为 1,而不是字节级别的答案 2。它也无法提供关于\207 是第一个连续字节还是第二个连续字节的信息,因为此处 RLENGTH 始终为 1。
$ gawk 'BEGIN{ print match("\353\200\207\352\277\254", "\207") }'
$ 1
$ gawk 'BEGIN{ match("\353\200\207\352\277\254", "\207\352");
$ print RSTART, RLENGTH }'
$ 1 2
$ gawk 'BEGIN{ print ("\300\353\200\207\352\277\254" ~ /\200/) }'
$ 1
match()
,还是使用Unicode无效/不完整参数的index()
,都会显示错误消息。$ gawk 'BEGIN{ match("\300\353\200\207\352\277\254", "\207\352"); print RSTART, RLENGTH }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 2 2
$ gawk 'BEGIN{ print index("\353\200\207\352\277\254", "\352") }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 0
$ gawk 'BEGIN{ print index("\353\200\207\352\277\254", "\200") }' gawk: cmd. line:1: warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale. 0
gawk
(因为它使用了gensub
)。 - rampion