Unixシステム上で値の列の合計を計算するための迅速かつ簡単な方法があると確信しています(おそらくawk
またはxargs
のようなものを使用します)が、解析するシェルスクリプトを書く行ごとに行が唯一頭に浮かぶものです。
たとえば、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 }'
任意の長い結果を得るためにbcでawkを使用する(Jouni K.
):
ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc
次のように、計算文字列を作成してbcに入力しようとします。
_ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc
_
これはawkのソリューションよりも少し長いように見えますが、奇妙な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 ' ' +) ))
_二重括弧の前後の間隔はオプションです。
all列を単純に追加するユーティリティスクリプトがあります。通常、1行の出力から必要なものを取得するのに十分簡単です。ボーナスとして、一部の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ソリューション
#!/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があります。
標準入力をピップラインの一部として処理する場合は、使用します
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:]] )
この質問はやや時代遅れですが、ここに「私の」答えが表示されないので、それでも投稿することにしました。私はの組み合わせで行きます
+
sign)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
私のシステムでこの特定の計算を行うことは実際には意味がありませんが、概念を示しています。
このソリューションのすべての部分は他の回答に示されていますが、その組み合わせでは決して示されていません。
cut
を介してデータを実行することで開始できます-少なくとも列を切り詰めます。
その後、それをgrep
にパイプして、非数値を取り除くことができるはずです。
その後...まあ、それから私はわからない。それをbc
にパイプすることが可能かもしれません。そうでない場合、各アイテムを追加するシェルスクリプトに確実に渡すことができます。
tr
を使用して改行を変更した場合(\n
)をスペース()に入れ、xargsを介してスクリプトにパイプし、入力がなくなるまでループし、それぞれを追加して、答えを得ることができます。
そのため、次のようなものがあります。
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}'
上記のPythonワンライナーに感謝します。ドライブの使用済みスペースを簡単に確認できました。これは、シェル/ Pythonの1つのライナーが混在しているため、デバイス/ 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 /少ないシェル:
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])"
再度、感謝します!
合計する特定の複数の列がある場合は、次を使用できます。
input_command | awk '{s1+=$1;s2+=$2;s3+=$3;s4+=$4;s5+=$5}END{print s1,s2,s3,s4,s5}'
列1〜5を合計する場合に機能します。