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
が完成する.