シェルで縦にずらっと出るものを、一定個ずつ横に並べたい話をします。
こんな入力
1
2
3
4
5
6
7
8
9
を
1 2 3
4 5 6
7 8 9
な感じにしたい。
xargs -L の場合
xargs を使って、引数を畳むテクニックがある。
-L
オプションで引数の個数を指定している。
xargs から入力を渡すコマンドを指定していない時、渡すコマンドは echo になる。
そのため「標準入力から読んで 1 行に n 個ずつ出力」ができる。
xargs
$ seq 1 9 | xargs -L 3
1 2 3
4 5 6
7 8 9
$
paste の場合
paste を使っても同じことができる。
paste は複数のファイルを 1 行に横につなげるコマンドで、
-
を指定した場合は標準入力から読む。
これが複数指定されると、標準入力から複数個ずつ取り出して出力する。
ただし区切り文字はタブなので、 -d' '
で区切り文字を指定する。
paste
$ seq 1 9 | paste -d' ' - - -
1 2 3
4 5 6
7 8 9
$
もっと大きな件数でやってみる
4096 件を 4 つずつ出力してみる。
自分の手元の環境だと大きな差がでた。
xargs -L の場合
xargs計測
$ time seq 1 4096 | xargs -L 4 > /dev/null
real 0m1.355s
user 0m0.592s
sys 0m0.648s
$
paste の場合
paste計測
$ time seq 1 4096 | paste -d' ' - - - - > /dev/null
real 0m0.007s
user 0m0.006s
sys 0m0.003s
$
理由
別シェルで ps してみたところ
psした時のある出力行
79968 ttys000 0:00.00 (echo)
のように echo が頻繁に表れ・消えしていた。
man ページを読んだ所、 xargs が使う echo は /bin/echo
のようだ。
xargs は必ず 1 プロセスを生成してしまうということ。
paste の方が速いのはこの差だと思う。
実験に使ったバージョン
- xargs (GNU findutils) 4.4.2
- paste (GNU coreutils) 8.21