ファイルや標準入力を指定行数で分割して、かつそれをそのまま(一時ファイルを作成せずに)次のコマンドに渡したいといったことがある。 例えば、以下のようなファイルがあったとして、5行ごとに合計を集計するといった処理をしたいとする。

blacknon@BS-PUB-DEVELOP:~$ cat test3.list
a01 13320
a02 64
a03 29730
a04 28184
a05 8993
b01 32490
b02 29077
b03 29590
b04 1291
b05 14097
c01 17676
c02 7998
c03 9720
c04 30072
c05 7565
d01 9220
d02 15714
d03 32185
d04 314
d05 10646
e01 29518
e02 15859
e03 10968
e04 30595
e05 27261

この場合、LinuxであればGNU拡張されたsplitコマンドが入っていると思う(Macではcore-utilsを入れればgsplitコマンドで使える)ので、「--filter="コマンド"」を使用することで、ファイルを分割せずにそのまま次のコマンドに渡す事ができる。 上記の処理をするなら、以下のようにsplitコマンドで--filterからawkを呼び出してやればいい。

cat test3.list | split -l 5 --filter="awk '{a+=\$2;print \$0}END{print \"TOTAL\",a}';echo --------"
blacknon@BS-PUB-DEVELOP:~$ cat test3.list | split -l 5 --filter="awk '{a+=\$2;print \$0}END{print \"TOTAL\",a}';echo --------"
a01 13320
a02 64
a03 29730
a04 28184
a05 8993
TOTAL 80291
--------
b01 32490
b02 29077
b03 29590
b04 1291
b05 14097
TOTAL 106545
--------
c01 17676
c02 7998
c03 9720
c04 30072
c05 7565
TOTAL 73031
--------
d01 9220
d02 15714
d03 32185
d04 314
d05 10646
TOTAL 68079
--------
e01 29518
e02 15859
e03 10968
e04 30595
e05 27261
TOTAL 114201
--------

ちなみに、splitコマンドを使わない場合について考えてみたのだが、以下のようなだいぶ無理やりな処理しか思いつかなかった。 ファイルの読み込みが2箇所あるし、あまりいい手法ではなさそうだ。

eval echo {1..$(cat test3.list|wc -l)..5} | xargs -n1 | xargs -I@ bash -c 'i=@;e=$(( @ + 5 - 1));sed -n "$i,$e p" test3.list|awk "{a+=\$2;print \$0}END{print \"TOTAL\",a}";echo ========'
blacknon@BS-PUB-DEVELOP:~$ eval echo {1..$(cat test3.list|wc -l)..5} | xargs -n1 | xargs -I@ bash -c 'i=@;e=$(( @ + 5 - 1));sed -n "$i,$e p" test3.list|awk "{a+=\$2;print \$0}END{print \"TOTAL\",a}";echo ========'
a01 13320
a02 64
a03 29730
a04 28184
a05 8993
TOTAL 80291
========
b01 32490
b02 29077
b03 29590
b04 1291
b05 14097
TOTAL 106545
========
c01 17676
c02 7998
c03 9720
c04 30072
c05 7565
TOTAL 73031
========
d01 9220
d02 15714
d03 32185
d04 314
d05 10646
TOTAL 68079
========
e01 29518
e02 15859
e03 10968
e04 30595
e05 27261
TOTAL 114201
========