最短的命令来计算在Unix上的一列输出的总和?

我确信有一个简单而快速的方法来计算Unix系统上一列值的总和(可能使用类似awkxargs ),但编写一个shell脚本来逐行parsing行是唯一的现在想起来了。

例如,修改下面的命令以计算并显示SEGSZ列(70300)的总数的最简单方法是什么?

 ipcs -mb | head -6 IPC status from /dev/kmem as of Mon Nov 17 08:58:17 2008 T ID KEY MODE OWNER GROUP SEGSZ Shared Memory: m 0 0x411c322e --rw-rw-rw- root root 348 m 1 0x4e0c0002 --rw-rw-rw- root root 61760 m 2 0x412013f5 --rw-rw-rw- root root 8192 
 ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }' 

或者没有尾巴:

 ipcs -mb | awk 'NR > 3 { sum += $7 } END { print sum }' 

使用aw和bc来得到任意长的结果(对Jouni K. ):

 ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc 

我会尝试构造一个计算string并将其按照如下所示提供给bc

  1. grep包含数字的行
  2. 在每行之前(和之后)将所有字符分开
  3. xargs结果(得到由空格分隔的一串数字)
  4. 将空格转换为“+”字符
  5. 好胃口BC

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc

看起来这比awk解决scheme稍长一些,但是对于那些无法阅读(并且理解)奇怪awk代码的人来说,这可能更容易理解…… 🙂

如果未安装bc,则可以在上面的步骤5中使用双括号来计算结果:

  • echo $(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))或者
  • SUM=$(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))或者
  • (( SUM=$(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))

双括号之前和之后的间距是可选的。

我有一个实用程序脚本,只是将所有列加起来。 通常很容易从单行输出中抓取你想要的。 作为奖励,一些SI后缀被识别。

 #!/usr/bin/awk -f # Sum up numerical values by column (white-space separated) # # Usage: $0 [file ...] # # stern, 1999-2005 { for(i = 1; i <= NF; ++i) { scale = 1 if ($i ~ /[kK]$/) { scale = 1000 } if ($i ~ /[mM]$/) { scale = 1000*1000 } if ($i ~ /[gG]$/) { scale = 1000*1000*1000 } col[i] += scale * $i; } if (NF > maxnf) maxnf = NF; } END { for(i = 1; i <= maxnf; ++i) { printf " %.10g", col[i] } print ""; } 

自定义字段分隔符的示例:

 $ head /etc/passwd | addcol -F: 0 0 45 39 0 0 0 

Python解决scheme

 #!/usr/bin/env python text= file("the_file","r") total= 0 for line in text: data = line.split() if data[0] in ('T', 'Shared', 'IPC'): continue print line segsize= int(data[6]) total += segsize print total 

大多数Linux发行版都有Python。

如果你想把stdin作为一个pipe道的一部分来使用,

 import sys total = 0 for line in sys.stdin: ...etc... 

如果你想假设总是有3个标题行:

 import sys total = 0 for line in sys.stdin.readlines()[3:]: total += int(line.split()[6]) print total 

一内胆:

 import sys; print sum( [int(line.split()[6]) for line in sys.stdin.splitlines()[3:]] ) 

你可以开始通过cut运行数据 – 至less会削减列。

然后,你应该能够将其转换为grep ,剥离非数字。

那么……那么我不确定。 这可能是pipe到bc 。 如果没有,它肯定可以交给一个shell脚本来添加每个项目。

如果您使用tr将换行符( \n )更改为空格( ),并通过xargs将其传递到您的脚本中循环,直到没有更多的input,添加每个input,您可能会有一个答案。

所以,类似于以下内容:

 cat <whatever> | cut -d'\t` -f7 | grep -v <appropriate-character-class> | tr '\n' ' ' | xargs script-that-adds-arguments 

我可能会把cut标记略微错了 – 但是man是你的朋友:)

你可以在任何在线awk参考中查找它:

 ipcs | awk ' BEGIN { sum = 0 } /0x000000/ { sum = sum + $2 } END {print sum}' 

我知道这个问题有些过时,但是我不能在这里看到“我的”答案,所以我决定张贴。 我会结合使用

  • 尾巴(得到你需要的线)
  • tr(将多个后继空间缩小到一个)
  • 剪切(只得到需要的列)
  • 粘贴(连接每一行+符号)
  • BC(做实际的计算)

ipcs不会给我的系统输出,所以我只是用df演示它:

 # df Filesystem 1K-blocks Used Available Use% Mounted on rootfs 33027952 4037420 27312812 13% / udev 10240 0 10240 0% /dev tmpfs 102108 108 102000 1% /run /dev/xvda1 33027952 4037420 27312812 13% / tmpfs 5120 0 5120 0% /run/lock tmpfs 204200 0 204200 0% /run/shm /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client1/web1/log /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client1/web2/log /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client1/web3/log /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client1/web4/log /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client2/web5/log /dev/xvda1 33027952 4037420 27312812 13% /var/www/clients/client2/web6/log # df | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2 | paste -s -d+ | bc 264545284 

我知道在我的系统上做这个特殊的计算并不合理,但它显示了这个概念。

所有这些解决scheme的部分已经在其他答案中显示,但从来没有在这个组合。

感谢上面的Python单行! 它帮助我轻松检查驱动器上的已用空间。 这是一个混合shell/ Python单行程,这样做 – 以兆字节计数/ dev / sda设备上的已用空间。 我花了一些时间,才发现它,所以,也许有人认为这也有用。

 df -h -B 1M | grep dev/sda | tr -s ' '| cut -d' ' -f3 |python -c "import sys; print sum([int(num) for num in sys.stdin.readlines()])" 

或更多的Python /less壳:

  df -h -B 1M | python -c "import sys; print sum([int(l.split()[2]) for l in sys.stdin.readlines() if '/dev/sda' in l])" 

再次感谢!