私が歌川です

@utgwkk が書いている

シェルで行ごとの数値の総和を取るとき paste と Arithmetic Expansion が使える

tl;dr

$ echo $((`paste -s -d+`))

で入力の各行の数値の総和が取れる. 入力ファイルを指定するときは次のように書く.

$ echo $((`paste -s -d+ < [filename]`))

負の整数も小数も計算できる.ただし小数は浮動小数であることに注意.

状況

たとえば,

100
200
300
400

みたいな入力があって,その各行の数値の総和をシェル上で取りたいというシチュエーションが訪れると思う. 私はこれまで awk で次のようなワンライナーを書いて計算していた.

$ awk '{s += $1} END {print s}' # => 1000

実はもっと短く書けるし,shとcoreutilsで完結しているのでシェルスクリプトでも気軽に書ける.このように;

$ echo $((`paste -s -d+`)) # => 1000

解説

paste -s -d+

paste は入力ファイルを行単位で連結するコマンドである.ファイル単位の zip と言えば伝わるかもしれない.

-s オプションを指定すると,1つのファイルの行を1行にまとめるようになる. -d オプションで,ファイルを連結するときの区切り文字を指定できる.デフォルトはタブ文字.

つまり,入力ファイルの行を区切り文字によって join することができるようになる.

$ paste -s -d+ # => 100+200+300+400

$((EXPR))

$((EXPR)) は,sh の機能*1で, EXPR を算術式として評価した結果で置換される.つまり,

$ echo $((1+2*3)) #=> 7

のように出力される.

まとめる

この2つと Command Substitution を組み合わせることで,

$ echo $((`paste -s -d+`)) # => 1000

が完成する.

参考

*1:もちろん bash でも zsh でも使える.