【问题标题】:awk logical conditions confusionawk 逻辑条件混乱
【发布时间】:2021-06-08 22:09:46
【问题描述】:

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

【问题讨论】:

  • 给定echo "one\ntwo\nthree\n",您的echo 输出版本是什么?大多数将完全输出带有文字\s 和ns 的字符串。如果您想在所有系统上的每个单词之间输出换行符(因此您的问题很清楚),请改用printf 'one\ntwo\nthree\n'

标签: if-statement awk logical-operators logical-and


【解决方案1】:

好的,有两件事:

  1. 我需要通过添加BEGIN {FS="\n"; RS=""} 来解析输入,以便 awk 将其视为单个记录
  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

【讨论】:

    【解决方案2】:
    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 987654334@ 在同一行,您的输入中没有任何案例),最后它打印每一行,不管发生了什么。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 2019-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多