たくさんあるデータを,シェルスクリプトで纏めて処理したいというニーズは多い.たとえば,たくさんの画像ファイルのサイズを一括で変換したいなど(これは本当によくある).で,こうやる.あ,次の例は「あるディレクトリに大量のJpegファイルがあって,そのサイズを半分にしたい」という設定ね.
$ for f in *.jpg; do
> convert -scale 50\% $f `basename $f .jpg`_s.jpg
> done
xargsでやろう
ところがxargs派の人々は「それxargsでおk」という.すなわち,
$ ls *.jpg \
| sed -e 's/.jpg//g' \
| xargs -I@ convert -scale 50\% @.jpg @_s.jpg
とやるのだ.basenameを使ったほうがわかりやすいという人は,
$ ls *.jpg \
| xargs -I@ basename @ .jpg \
| xargs -I@ convert -scale 50\% @.jpg @_s.jpg
でもOK.ただし,私は,ちょっとコレには受動態が続く文章のような気持ち悪さを感じる.ま,それはそれとして.
xargsに対してはどうも好き嫌いがあるようで,周辺に聞き込みしたところ,オジサンたちより若者に支持されている傾向があるような……(まあサンプル数が少ないので,半分冗談ですw).で,なんでxargsに抵抗感を感じるのかなと考えてみた.抵抗感のもとは何か,それは,xargsは「一刀両断」ということなんだな.つまり,「並べた処理対象をパイプで流し込んで,コマンド一発!」という,データ集合に対してmapでドン!といったイメージというか.
for派の主張
「for文」派の思考過程は,こんな感じ.先の例みたいな簡単な例ではなくて,もう少しフクザツなケースを考えてみるよ.
- まずひとつのデータを対象として,試行錯誤してみる.「cat file01.xxx | commandA | commandB | ... > file01.yyy」という感じ.これは,シェルスクリプトがインタラクティブに処理できるメリットを最大限に享受できて,いちいち中間の結果を確かめながら作業できるので,作業効率がよい.
- ある程度処理がうまくいくことを確認したら,for文で囲む.上の例でいえば,「for f in *.xxx; do cat $f | commandA | commandB | ... > `basename $f .xxx`.yyy; done」とする.
xargsを使ってコレをやろうとすると,2.の過程で一連の作業をパッケージングしなければいけない.関数にするとか.名前付けてあげないと「mapでドン!」ができないから.そこに,思考のギャップがあって,それに違和感をオジサンたちは感じるんじゃないだろうか.
抽象度を高めてmapでドン方式のほうが,並列化が簡単だとか,いろいろメリットがあるのもわかる.しかしそれは一方でデメリットでもあって,記述のイメージと実際のデータ処理がマッチしてないので想像力を求められるという面もある.パイプでコマンドを繋いでいくというシェルの書き方はデータの流れとコマンド列が見た目で対応していて実に自然な感じなのに,xargs使うといきなり並列化しちゃうので,混乱するのだ.(私を含め)オジサンたちはそこについて行けない.
具体例と対策
まあ,話をもう少し身近な例に戻そう.ちょっと時間がかかる処理を大量のデータに対して適用するときは,進捗状況をechoで確認しながらやることが多い.たとえば冒頭の例で示すと,こうやる.
$ for f in *.jpg; do
> echo -n converting $f ...
> convert -scale 50\% $f `basename $f .jpg`_s.jpg
> echo done
> done
これxargsで,どうやるの?教えてxargsの偉い人!
……と,ここまで書いて公開したら,いろいろとコメントでアドバイスを頂いた.面白い議論ができたというところ.その議論でxargsに関してたいへん理解を深めることができたが,結論としては,次のように -t オプション(もしくは--verbose,実行内容を標準エラー出力に表示するもの)を指定すればよいとのこと.
$ ls *.jpg \
| sed -e 's/.jpg//g' \
| xargs -t -I@ convert -scale 50\% @.jpg @_s.jpg
なんでもよいのでいくつかファイルがあるところで次を実行してみると,動作がよくわかる.これでxargsに親しむことができれば,いつまでもforeachに拘るオジサンから成長できるんじゃないかな……
0 件のコメント:
コメントを投稿