最短的命令来计算在Unix上的一列输出的总和?
我确信有一个简单而快速的方法来计算Unix系统上一列值的总和(可能使用类似awk
或xargs
),但编写一个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 :
- grep包含数字的行
- 在每行之前(和之后)将所有字符分开
- xargs结果(得到由空格分隔的一串数字)
- 将空格转换为“+”字符
- 好胃口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])"
再次感谢!