xargsとGNU Parallelの個別の解説記事や、比較の解説記事は多いようだが、両者を組み合わせて使うと便利であることに気が付き、その解説は少なくとも日本語では見つからないので、以下に解説。
多数のファイルを処理する場合の工夫
- ここでは「多数のファイルを処理する場合の工夫」と書いたが、ここには分かり安い例示はない。
- 例示が大きくなりがちなために、例を載せるのがやや困難なため。
- 従って、下記のコマンド例を実行すれば意味が分かって、cheat sheetのように後で読み返しやすい様に、要点のみを記す。
- 下記は、あくまで__数万個__のファイルを対象にする場合である。
- 数百万個もある場合は、下記の方法だと、各コマンドの起動が10ミリ秒であっても、計算が1日(86400秒)程度かかる。
- そのような場合は、各コマンドが、数百個のファイルを一度に処理するように工夫すれば良い。そうすると、場合によっては、ここに書いてあるノウハウが再び役に立つであろう。
下記の状況を仮定する
- 1個のディレクトリに__数万個のデータファイル__が存在する。
- 何かの処理を手際よく処理したい。
- 再現性を高い状態にして、保守性を高めたい。
数万個のファイルが1個のディリクトリにある場合の難点
-
ls
は何かを表示するまでの時間がかかる。- 比較すると
echo *
が何倍も高速。
- 比較すると
-
less *
とするとtoo long
などという警告が出て動かない。- これは、
echo * | xargs -n 1000 less
で対処可能。
- これは、
その場合の対処法
-
シェルの
for
句を使う — 繰り返し処理の指定が簡単に書ける。- シェルのfor句の簡単な例:
for i in `seq 10` ; do echo $i ; done
- シェルのfor句の簡単な例:
-
GNU Parallelを使う — プロセスの並列化が容易に出来て、処理が何倍も速くなる。
- インストールして、コマンドの
parallel
を用いる。 - 例えば次の様な使い方をする。
echo * | xargs -n1000 | parallel -C ' ' wc
- よく使われているかも知れない使い方:
-
:::
や::::
を使った構文の方がもっと基本的かもしれない。 -
{}
や{1}
などを使った書き方も要マスター。
-
- しかし、下記で書いたようなことが、私には必要ではあった。
- 上記の状況への対処に、どうやら xargsのみだと何かが足りない。
- parallelを使うと一見複雑だが、最も簡潔そうである。
- インストールして、コマンドの
-
Makefileを使う — 保守性と再現性が高まる。
- 複数の処理にそれぞれ名前を付けて、必要な時に必要な処理が出来る。
-
make proc1 proc2
などを実行すれば良い。
-
- ひとつのファイルに、それらの複数の処理内容を書けるので、保守が楽。
- ただし、シェルのコマンド文中の
$i
は$$i
と書き換えたりなどの工夫が厄介かも。
- ただし、シェルのコマンド文中の
- 複数の処理にそれぞれ名前を付けて、必要な時に必要な処理が出来る。
parallelとシェルのfor句を組み合わせる
- for文と組み合わせない例(#) :
seq 20 | xargs -n8 | parallel -C ' ' echo
- for文を組み合わせる例:
-
seq 20 | xargs -n8 | parallel -C ' ' for i in {} \; do echo \$i \; done
。 - 上記では、次の様な書き換えが必要となった。
-
$
と;
をエスケープする。parallelに渡す前に直接シェルに解釈させないため。 -
|
,"
,(
,)
,<
,>
,'
などもエスケープが必要。
-
-
seq 20 | xargs -n8 | parallel -C" " ' for i in {}; do echo $i ; done | tr "\n" " "'
とすると、もっと単純。- シングルクォート
'
の間に改行文字を含めてよく、簡単に複数行のコマンド文を埋め込むことが出来る。
- シングルクォート
-
Parallelに関して(引用に関する表示)
bash-3.2$ parallel --citation
Academic tradition requires you to cite works you base your article on.
If you use programs that use GNU Parallel to process data for an article in a
scientific publication, please cite:
@software{tange_2021_5593566,
author = {Tange, Ole},
title = {GNU Parallel 20211022 ('Sinclair')},
month = Oct,
year = 2021,
note = {{GNU Parallel is a general parallelizer to run
multiple serial command line programs in parallel
without changing them.}},
publisher = {Zenodo},
doi = {10.5281/zenodo.5593566},
url = {https://doi.org/10.5281/zenodo.5593566}
}
(Feel free to use \nocite{tange_2021_5593566})
This helps funding further development; AND IT WON'T COST YOU A CENT.
If you pay 10000 EUR you should feel free to use GNU Parallel without citing.
More about funding GNU Parallel and the citation notice:
https://lists.gnu.org/archive/html/parallel/2013-11/msg00006.html
https://www.gnu.org/software/parallel/parallel_design.html#Citation-notice
https://git.savannah.gnu.org/cgit/parallel.git/tree/doc/citation-notice-faq.txt
If you send a copy of your published article to tange@gnu.org, it will be
mentioned in the release notes of next version of GNU Parallel.