我试图用标准的awk
调用来模拟GNU grep -Eo
。
该男子对-o
选项的说法是:
-o --only-matching
仅打印匹配行的匹配(非空)部分,每个部分在单独的输出行上。
现在我有这个代码:
#!/bin/sh
regextract() {
[ "$#" -ge 2 ] || return 1
__regextract_ere=$1
shift
awk -v FS='^$' -v ERE="$__regextract_ere" '
{
while ( match($0,ERE) && RLENGTH > 0 ) {
print substr($0,RSTART,RLENGTH)
$0 = substr($0,RSTART+1)
}
}
' "$@"
}
我的问题是:如果匹配的部分是0-length
,我需要继续尝试匹配剩下的行,还是应该移动到下一行(就像我已经做的那样)?我找不到需要前者的input+regex示例,但我觉得它可能存在。有什么想法吗?
4条答案
按热度按时间k4aesqcs1#
下面是一个POSIX awk版本,它可以与
a*
(或任何POSIX awk regex)一起使用:图纸:
POSIX awk和
grep -E
使用POSIX扩展正则表达式,除了awk允许C转义(像\t
),但grep -E
不允许。如果你想要严格的兼容性,你必须处理这个问题。fcipmucu2#
如果您可以考虑
gnu-awk
解决方案,那么使用RS
和RT
可能会给予grep -Eo
的相同行为。使用
grep -Eo
:使用
gnu-awk
与RS
和RT
使用相同的正则表达式:更多示例:
pxiryf3j3#
感谢各种各样的评论和回答,我认为我现在有一个工作的,健壮的,(也许)高效的代码:
在AIX/Solaris/FreeBSD/macOS/Linux上测试
备注:
awk
就不会预处理它(感谢@anubhava指出这一点);C风格的转义序列仍然会被awk
的正则表达式引擎翻译(感谢@dan指出这一点)。$0
会重置所有字段的值,所以我选择FS = '^$'
来限制开销在一个单独的变量中复制
$0
可以抵消在while
循环中分配$0
所引起的开销(感谢@EdMorton指出这一点)。几个例子:
pqwbnv8z4#
您的代码将无法匹配可能包含零个或多个字符的字符,请考虑以下简单示例,让
file.txt
内容为然后
给出输出
你的
while
的条件是match($0,ERE) && RLENGTH > 0
,在这种情况下,前一部分为true,但后一部分为false,因为在第一个字符之前找到的匹配是零长度(RSTART
被设置为1
),因此while
的主体将被执行零次。