【问题标题】:How to efficiently sum two columns in a file with 270,000+ rows in bash如何在 bash 中有 270,000 多行的文件中有效地对两列求和
【发布时间】:2014-05-05 08:40:25
【问题描述】:

我在一个文件中有两列,我想自动对每行的两个值求和

例如

read write
5    6
read write
10   2
read write
23   44

然后我想总结每一行的“读取”和“写入”。最终在求和之后,我找到了最大和并将该最大值放入文件中。我觉得我必须使用 grep -v 来删除每行的列标题,正如答案中所述,这会使代码效率低下,因为我只是为了读取一行而对整个文件进行 grep。

我目前在 bash 脚本中(在 $x 是文件名的 for 循环中)对列进行逐行求和

lines=`grep -v READ $x|wc -l | awk '{print $1}'`
line_num=1
arr_num=0


while [ $line_num -le $lines ]
do

    arr[$arr_num]=`grep -v READ $x |  sed $line_num'q;d' | awk '{print $2 + $3}'`
    echo $line_num
    line_num=$[$line_num+1]
    arr_num=$[$arr_num+1]

done

但是,要求和的文件有 270,000 多行。该脚本已经运行了几个小时,但还远未完成。有没有更有效的方法来写这个,这样它就不会花这么长时间?

【问题讨论】:

  • 位非正统..从那里导入数据库和SUM?
  • 不清楚 READ 的挂断是什么;我怀疑你没有告诉我们关于输入数据格式的全部故事。
  • 您的脚本正在读取整个文件,为每一行提取一行。难怪它需要很长时间。
  • 为 while 循环的每次迭代调用 grepsedawk 可能是导致性能问题的主要因素。特别是考虑到grep 在每次迭代中都有效地读取了整个文件
  • 你需要知道行号是什么吗?你想要的输出格式到底是什么?

标签: bash unix solaris performance


【解决方案1】:

改用 并利用模数函数:

awk '!(NR%2){print $1+$2}' infile

【讨论】:

  • 我在我的问题中更改了源文件的格式,因为这是相关的。我忘了提那个。这就是为什么我必须使用 grep
【解决方案2】:

为什么不跑:

awk 'NR==1 { print "sum"; next } { print $1 + $2 }'

您可以在其他脚本仍在运行时在文件上运行它。它最多会在几秒钟内完成(预测)。当你确信它是正确的时,你可以杀死另一个进程。

如果您愿意,可以使用 Perl 或 Python 代替 awk

您的代码在输入文件的每一行都运行grepsedawk;那可真是贵死了。它甚至没有将数据写入文件;它正在 Bash 的内存中创建一个数组,稍后需要将其打印到输出文件中。

【讨论】:

    【解决方案3】:

    awk 可能更快,但惯用的 方法类似于:

    while read -a line; do      # read each line one-by-one, into an array
                                # use arithmetic expansion to add col 1 and 2
        echo "$(( ${line[0]} + ${line[1]} ))"
    done < <(grep -v READ input.txt)
    

    请注意,文件输入文件仅读取一次(grep),并且外部分支程序的数量保持在最低限度(仅grep,整个输入文件仅调用一次)。其余命令为bash builtins。

    使用&lt;( ) 进程替换,以防需要在while 循环中设置的变量超出while 循环的范围。否则可以使用| 管道。

    【讨论】:

    • 谢谢!我现在必须在星期五试一试。当我尝试时,我会给你更多的信任。
    【解决方案4】:

    您的问题很冗长,但您的目标并不明确。我读它的方式,你的数字在每一行,你只想找到最大的总和。鉴于:

    awk '
        NR%2 == 1 {next} 
        NR == 2 {max = $1+$2; next} 
        $1+$2 > max {max = $1+$2}
        END {print max}
    ' filename
    

    【讨论】:

    • 用你的方法对两列求和:awk 'NR>2{sum+=$4-$5}END{print sum}' file
    【解决方案5】:

    假设它总是一个“标题”行后跟一个“数据”行:

    awk '
      BEGIN{ max = 0 }
      {
        if( NR%2 == 0 ){
          sum = $1 + $2;
          if( sum > max ) { max = sum }
        }
      }
      END{ print max }' input.txt
    

    或者干脆剪掉所有不符合你想要的行:

    grep '^[0-9]\+\s\+[0-9]\+$' input.txt | awk '
      BEGIN{ max = 0 }
      {
        sum = $1 + $2;
        if( sum > max ) { max = sum }
      }
      END{ print max }' input.txt
    

    【讨论】:

      【解决方案6】:

      您还可以使用带有隐式循环输入的工具的管道,如下所示:

      grep -v read INFILE | tr -s ' ' + | bc | sort -rn | head -1 > OUTFILE
      

      这假设您的读取和写入数据值之间存在空格。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 2022-08-17
        • 1970-01-01
        相关资源
        最近更新 更多