web-dev-qa-db-ja.com

Unixで出力の列の合計を計算する最短コマンド?

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
48
An̲̳̳drew
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に入力しようとします。

  1. grep数字を含む行
  2. sed各行の番号の前(および後)にあるすべての文字を取り除く
  3. xargs結果(空白で区切られた数字の文字列を取得するため)
  4. tr空白を「+」文字に置き換えます
  5. 良い食欲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 ' ' +) ))_

二重括弧の前後の間隔はオプションです。

13
Peterino

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
4
user61853

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:]] )
2
S.Lott

この質問はやや時代遅れですが、ここに「私の」答えが表示されないので、それでも投稿することにしました。私はの組み合わせで行きます

  • tail(必要な行を取得するため)
  • tr(複数の結果スペースを1つに縮小するため)
  • cut(必要な列のみを取得する)
  • 貼り付け(各行を+ sign)
  • 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

私のシステムでこの特定の計算を行うことは実際には意味がありませんが、概念を示しています。

このソリューションのすべての部分は他の回答に示されていますが、その組み合わせでは決して示されていません。

2

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はあなたの友達です:)

1
warren

オンラインのawkリファレンスで調べることができます。

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

上記の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])"

再度、感謝します!

0
Andrzej

合計する特定の複数の列がある場合は、次を使用できます。

input_command | awk '{s1+=$1;s2+=$2;s3+=$3;s4+=$4;s5+=$5}END{print s1,s2,s3,s4,s5}'

列1〜5を合計する場合に機能します。

0
gerrit