0

有人可以解释为什么这会按预期工作:
echo "one\ntwo\nthree\n" | awk '{if (gsub(/one/,"")) { print } else {print $0}}'


two
three

echo "one\ntwo\nthree\n" | awk '{if (gsub(/four/,"")) { print } else {print $0}}'

one
two
three

但这不是吗?
echo "one\ntwo\nthree\n" | awk '{if (gsub(/one/,"")) { print }}'


类似地,如果尝试链接多个替换,则要求所有替换都返回发生替换的非零计数,然后才打印更改后的结果,否则打印原始内容:
echo "one\ntwo\nthree\n" | awk '{if (gsub(/one/,"") && gsub(/two/,"")) { print } else {print $0}}'

我正进入(状态:


two
three

我期望的地方:



three

我在这里想念什么?来自任何其他编程语言,我希望这能够“正常工作”。请注意,我在 BSD 和 GNU awk 中观察到相同的行为。

编辑:

我认为这与 awk 如何处理多行输入有关:

echo "one\ntwo\nthree\n" | awk '{if (gsub(/one/,""))  print "found"; else print "not found"  }'

found
not found
not found
not found
4

2 回答 2

1
printf 'one\ntwo\nthree\n' | awk '{if (gsub(/one/,"")) { print }  else {print $0}}'

可以简化为:

printf 'one\ntwo\nthree\n' | awk '{gsub(/one/,""); print}'

因为它只是从每一行中删除one(如果存在)并打印每一行。

另一方面,您失败的脚本:

printf 'one\ntwo\nthree\n' | awk '{if (gsub(/one/,"")) { print }}'

可以简化为:

printf 'one\ntwo\nthree\n' | awk 'gsub(/one/,"") { print }'

从每一行中删除one(如果存在),但它只打印那些gsub()返回非零数字的行,即至少删除 1 one

您发布的另一个脚本:

printf 'one\ntwo\nthree\n' |
awk '{if (gsub(/one/,"") && gsub(/two/,"")) { print }  else {print $0}}'

可以简化为:

printf 'one\ntwo\nthree\n' |
awk 'gsub(/one/,""){ gsub(/two/,"") } { print }'

因此它会尝试删除ones ,如果成功则尝试删除twos(因此它永远不会尝试删除在同一行上two没有 a 的 a one,您的输入中没有任何情况)和不管发生了什么,它都会打印每一行。

如果您想始终删除ones 和twos 并打印每一行,那么那就是:

printf 'one\ntwo\nthree\n' |
awk '{gsub(/one/,""); gsub(/two/,""); print }'
于 2021-03-11T01:36:31.783 回答
0

好的,所以有两件事:

  1. 我需要解析输入,以便 awk 将其视为单个记录,方法是添加BEGIN {FS="\n"; RS=""}
  2. 我混淆了printprint $0用法,认为前者存储了修改输入的当前值,而后者存储了原始值,但它们都只存储当前值。

所以我最后一个问题的解决方案是:

echo "one\ntwo\nthree\n" | awk 'BEGIN {FS="\n"; RS=""}{orig=$0;if (gsub(/one/,"") && gsub(/two/,"")) { print }  else {print orig}}'


three
于 2021-03-10T23:24:14.467 回答