awk 逻辑条件混乱

问题描述

有人可以解释一下为什么这会按预期工作:
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

解决方法

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 }'

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

如果您想始终同时删除 onetwo 并打印每一行,则应该是:

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

好的,有两件事:

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

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

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


three

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...