谁能解释一下为什么这个工作是预期的:echo "onentwonthreen" | awk '{if (gsub(/one/,"")) { print } else {print $0}}'
two
three
echo "onentwonthreen" | awk '{if (gsub(/four/,"")) { print } else {print $0}}'
one
two
three
但是这个没有?echo "onentwonthreen" | awk '{if (gsub(/one/,"")) { print }}'
同样,如果试图链接多个替换,要求它们都返回发生替换的非零计数,然后只打印更改的结果,否则打印原始内容:echo "onentwonthreen" | awk '{if (gsub(/one/,"") && gsub(/two/,"")) { print } else {print $0}}'
我得到了:
two
three
我期望的地方:
three
我在这里错过了什么?从任何其他编程语言来看,我希望这"只是工作"。请注意,我在BSD和GNU awk中观察到相同的行为。
编辑:
我认为这与awk处理多行输入的方式有关:
echo "onentwonthreen" | awk '{if (gsub(/one/,"")) print "found"; else print "not found" }'
found
not found
not found
not found
printf 'onentwonthreen' | awk '{if (gsub(/one/,"")) { print } else {print $0}}'
可以简化为:
printf 'onentwonthreen' | awk '{gsub(/one/,""); print}'
,因为它只是从每行删除one
,如果存在,并打印每行。
另一方面,你失败的脚本:
printf 'onentwonthreen' | awk '{if (gsub(/one/,"")) { print }}'
可简化为:
printf 'onentwonthreen' | awk 'gsub(/one/,"") { print }'
从每行删除one
(如果存在),但它只打印gsub()
返回非零数字的行,即删除至少1个one
。
你发布的另一个脚本:
printf 'onentwonthreen' |
awk '{if (gsub(/one/,"") && gsub(/two/,"")) { print } else {print $0}}'
可以简化为:
printf 'onentwonthreen' |
awk 'gsub(/one/,""){ gsub(/two/,"") } { print }'
所以它尝试删除one
s和如果成功,则它试图删除twos
(所以它永远不会试图删除没有one
的two
在同一行,你的输入中没有任何情况),最后它打印每一行,不管发生了什么。
如果你想总是删除one
s和two
s并打印每一行,那么这将是:
printf 'onentwonthreen' |
awk '{gsub(/one/,""); gsub(/two/,""); print }'
好了,有两件事:
- 我需要解析输入,以便awk将其视为单个记录,通过添加
BEGIN {FS="n"; RS=""}
- 我混淆了
print
和print $0
的用法,认为前者存储修改后输入的当前值,而后者存储原始值,但它们都只存储当前值。
所以我最后一个问题的解决方案是:
echo "onentwonthreen" | awk 'BEGIN {FS="n"; RS=""}{orig=$0;if (gsub(/one/,"") && gsub(/two/,"")) { print } else {print orig}}'
three