我有一个包含数千个数字的文件,每个数字都在自己的行上:

34
42
11
6
2
99
...

我想写一个脚本,它将打印文件中所有数字的总和。我有一个解决办法,但不是很有效。(运行需要几分钟。)我在寻找一个更有效的解决方案。有什么建议吗?


当前回答

另一个是为了好玩

sum=0;for i in $(cat file);do sum=$((sum+$i));done;echo $sum

或者再来一次

s=0;while read l; do s=$((s+$l));done<file;echo $s

但awk解决方案可能是最好的,因为它最紧凑。

其他回答

$ perl -MList::Util=sum -le 'print sum <>' nums.txt

你可以使用awk:

awk '{ sum += $1 } END { print sum }' file

GNU Parallel可以通过将工作负载分散到多个核心来改进上面的许多问题。

在下面的例子中,我们将500个数字的块(——max-lines=500)发送给bc进程,这些进程一次并行执行4个(-j 4)。然后,结果由最终的bc聚合。

time parallel --max-lines=500 -j 4 --pipe "paste -sd+ - | bc" < random_numbers | paste -sd+ - | bc

工作规模和并行过程数量的最佳选择取决于机器和问题。请注意,这种解决方案只有在存在大量并行流程且每个流程都有大量工作时才会真正发挥作用。

下面是一个使用python和生成器表达式的解决方案。在我破旧的笔记本电脑上测试了无数个数字。

time python -c "import sys; print sum((float(l) for l in sys.stdin))" < file

real    0m0.619s
user    0m0.512s
sys     0m0.028s

在去:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    sum := int64(0)
    for scanner.Scan() {
        v, err := strconv.ParseInt(scanner.Text(), 10, 64)
        if err != nil {
            fmt.Fprintf(os.Stderr, "Not an integer: '%s'\n", scanner.Text())
            os.Exit(1)
        }
        sum += v
    }
    fmt.Println(sum)
}