ファイルや標準入力を指定行数で分割して、かつそれをそのまま(一時ファイルを作成せずに)次のコマンドに渡したいといったことがある。
例えば、以下のようなファイルがあったとして、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 ========
