Linuxに不慣れな私が頑張ってシェルスクリプトで並列実行しようとした時の備忘録。

 下記のコマンドは動作確認してはいないので、万が一この記事を参考にしようとしているのなら十分に注意されたい。

目的

 ディレクトリ"text"内に、"test1.txt"、"test2.txt"、...、"testN.txt"というファイルがある。Nは連番になっているわけではなく、飛び飛びであるか、場合によっては数字ではないかもしれない。このファイルをあるプログラム"test_process"に渡して実行したい。

text_process ../test/test1.txt hogehoge

 ただしtest_processはとても時間のかかる処理なので、並列に実行したい。かつtestN.txtはスレッド数よりもずっと多いので、同時実行数は常にCPUコア数までとし、余剰分はコアに空きが出るまで待機させる。スレッドプールみたいなイメージである。

方法

 lsとxargsの2つのコマンドを組み合わせる。
 lsは知らない人のいないコマンドなので詳しい説明は省略するとして、testディレクトリ中のtestN.txtの一覧を取得するには次のようにすればよい。

ls test/test*.txt -1

 -1は見つかったファイルを1行ずつ改行しながら出力する。今回は特に必要はないと思うが、一応付けた。xargsで-Lオプションないし-nオプションを使う場合は改行以外の空白文字の取り扱いが変わってくるようなので、これの有無が影響するのかもしれない。
 findコマンドでも出来るのだろうが、違いはよく知らない。

 この出力結果をxargsへと渡す。

ls test/test*.txt -1 | xargs -P 6 -IAAA test_process AAA hogehoge

 このとき-Pオプションが同時実行数の指定。ここでは6個までtest_processを同時実行する。-Iオプションはlsコマンドの出力を1つずつ"AAA"という名前で受け取るという意味に解釈される。よってこの引数"AAA"をそのままtest_processの引数にしてやればよい。こうすることで、

test_process test/test1.txt hogehoge
test_process test/test2.txt hogehoge
...
test_process test/testN.txt hogehoge

というような感じで、test_processが最大6個まで同時に実行されていく。

その他

 今回、test_processの引数が"AAA hogehoge"という並びであったため、-Iオプションを用いた。もしhogehogeという追加の引数がなければ、あるいは"hogehoge AAA"という並びであったのなら、-Lまたは-nオプションでも可能だった。
 xargsがパイプから受け取った引数は、例えば

ls test/test*.txt -1 | xargs test_process hogehoge

のように-I、-L、-nいずれのオプションも与えずに実行した場合、

test_process hogehoge test/test1.txt test/test2.txt ... test/testN.txt

と、全てが一度にtest_processへと渡されてしまう。この引数の展開は必ずhogehogeの後に続き、hoehogeよりも前に配置することは出来ないようだ。
 引数が丸ごと展開されないようにするには、上述のように-Iオプションを使う方法もあるが、その他に-Lまたは-nオプションを使うこともできる。

ls test/test*.txt -1 | xargs -P 6 -L(or -n) 1 test_process hogehoge

こうすることで、

test_process hogehoge test/test1.txt
test_process hogehoge test/test2.txt
...
test_process hogehoge test/testN.txt

と1つずつ渡されるようになる。-L、-nの後に続く数字は、lsコマンドからの引数をいくつずつ展開するかを指示している。今回は1を与えたのでtest/testN.txtは一つずつtest_processに与えられた。  -Lオプションはlsコマンドの出力に対して、改行のみを区切りとみなし、それ以外の空白文字は区切り文字として扱わない。なのでlsコマンドに-1を与えておかないと、全ての出力結果が区切られることなくtest_processに渡されてしまう、と思われる。
 -nオプションは空白文字全般を区切り文字とみなすので、-1がなくても動くはず。
この微々たる違いにどのような意義があるのかはよく分からないが、例えばtest_processに与える引数の数が固定ではなく毎回異なっている場合、-Lオプションの"改行以外を区切りとして扱わない"性質が役立つ気はする。