【问题标题】:How to find negaive numbers from each line and print only once using shell script如何使用 shell 脚本从每一行中查找负数并仅打印一次
【发布时间】:2016-06-12 14:18:50
【问题描述】:

我想从输入文件的每一行中找到负数(相同的值)。 如果一行中没有负数,它将打印 0。如果负数出现不止一次,它将打印一次负数。例如 输入文件是(input.txt):

 1       0       0       0       0       0       0       0       0
 1       1      -1       0      -1       0       1       0       0
 1       1       0      -1       0       0       1       0      -1
 1       1       0       0      -1       0       0       0       0

想要的输出是:

 0
-1
-1
-1

目前我正在使用

awk '{for(i=1; i<=NF;i++)if($i ~ /^-/) {printf "%s\n",$i}}' input.txt > output

但它不会在第一行产生 0,而是打印所有 -1。 有没有聪明的办法解决这个问题?

【问题讨论】:

  • 如果输入的最后一行是1 1 0 0 -1 0 -5 0 -2 那么输出什么?
  • 不,每行只有相同类型的 -ve 数字。比如在第 2 或第 3 或第 4 行中的 -1。
  • 所以每个单元格中只能有-1 or 0 or 1
  • 如果只有一个负数会怎样?您想要的输出似乎表明一个被视为许多,尽管在您的描述中没有定义。
  • 是的。但是,如果脚本不知道 +ve 数字并且只看到每行中相同的 -ve 数字(如 -1),那就太好了。

标签: bash awk sh


【解决方案1】:

您可以在 bash 中通过简单的模式匹配来做到这一点,无需 awk。

while read line; do
  if [[ $line = *-1* ]]; then
    echo -1
  else
    echo 0
  fi
do < inputfile

或缩短为单行:

while read l; do [[ $l = *-1* ]] && echo -1 || echo 0; done < inputfile

或者 sed 可以这样做:

sed '/-/s/.*/-1/;/-/!s/.*/0/' inputfile

或者,如果您愿意以简单换取性能:

sed -e '/-/s/.*/-1/;t' -e 's/.*/0/' inputfile

【讨论】:

  • 你可以在 awk 中通过简单的模式匹配来做到这一点,不需要 bash :-)。
  • 啊,Ed,我希望你今天不在。呃,好吧! :-D (虽然,bash 单行也是一个单一的模式匹配,相当于你的 awk 解决方案,虽然多一点打字。)
  • 那么你们这些讨厌的家伙只会失控,然后我们会在哪里:-)。除了额外的输入之外,bash 循环的主要问题是它比 awk 或 sed 解决方案慢一个数量级。 idk 如果这对 OP 来说是个问题,当然。
  • 我刚刚测试了 100k 行。结果很有趣。 Bash 实际上慢了几个数量级。结果是:awk=0.13s, sed=2.27s, bash=2.1s。 sed 解决方案会稍微快一些 - 2.1 秒 - 如果我根据我更新的答案使其单匹配......但根据这些测试,awk(正如你所使用的那样)显然是性能更高的解决方案。跨度>
  • 我很惊讶 sed 这么慢,但看起来你的数据显示 bash is 比 awk 慢一个数量级:awk=0.13sbash=2.1s。我想我以后不会假设 sed 的表现不错!感谢您的检查。对于其他阅读本文并想了解为什么 shell 循环如此缓慢的人,请参阅 Stephane 在unix.stackexchange.com/q/169716/133219 的回答。
【解决方案2】:

你可以使用这个 awk:

awk '{p=0; for(i=1; i<=NF;i++) if ($i<0) {p=$i; break} print p}' file

0
-1
-1
-1

【讨论】:

    【解决方案3】:
    $ awk '{print (/-/?-1:0)}' file
    0
    -1
    -1
    -1
    

    我假设:

    1. 你不能用-2s 代替-1s,或者
    2. 如果发生这种情况,您仍然需要-1 输出

    因为如果有可能发生-2s 行而不是-1s 并且希望在这种情况下输出-2,那么在您的示例输入中包含这将是一件显而易见的事情/输出。

    【讨论】:

      【解决方案4】:

      根据您的问题描述,您可以使用这个:

       awk '/-/{print "-1"}!/-/{print "0"}' file
      

      【讨论】:

        猜你喜欢
        • 2021-12-20
        • 1970-01-01
        • 2015-05-26
        • 2015-07-04
        • 1970-01-01
        • 2018-06-26
        • 2017-10-02
        • 1970-01-01
        • 2021-11-19
        相关资源
        最近更新 更多