GNU parallel でコマンドの並列処理を実現する
複数ファイルに対して一気に特定のコマンドを動かしたいとき、大量の URL を与えられたときそのすべてをダウンロードしたい、そんなときに parallel が使える。parallel は例えばコマンドの引数 (echo <args>
の <args>
) を変数として受け取ってコマンドを並列実行できるので、前述のような処理をするのに便利である。
前提
- Ubuntu 24.04
インストール
Ubuntu 24.04 の parallel は古すぎるので openSUSE Build Service から Debian Unstable のものをダウンロードしてインストールする。
wget https://download.opensuse.org/repositories/home:/tange/Debian_Unstable/all/parallel_20250122_all.deb
sudo apt install ./parallel_20250122_all.deb
使い方
引数を使った並列実行
最もシンプルな使い方は、変数としたい部分をリスト引数として parallel に与える方法である。
parallel <command> ::: <args1> [args2] [args3] ...
例えば echo
コマンドを用いると以下のようになる。
parallel echo ::: 1 2 3
1
2
3
標準出力 / ファイルを用いた並列実行
parallel は標準出力を入力として受け取ることができる。
seq 3 | parallel echo
1
2
3
seq 3
の部分を例えば ls *.jpg
とすれば、カレントディレクトリにある JPEG ファイルだけを parallel に渡せる。ImageMagick 等と組み合わせると画像処理に便利である。
cat
などを用いればファイルの中身を標準出力に流せる。
cat files.txt
d.txt
e.txt
f.txt
cat files.txt | parallel echo {.}
d
e
f
ファイルに URL を書いておいて、cat urls.txt | parallel wget
と実行すれば URL 先のコンテンツをいっぺんにダウンロード出来て便利である。
引数(入力テキスト)の処理
parallel は引数を受け取った後、その内容を加工することができる。このとき引数は明示的に {}
で受け取るようにする。man parallel
の OPTIONS 節に色々書いてあるのでそちらも参考のこと。
なお、カレントディレクトリには以下のファイルがあるものとする。
echo $PWD
/home/ubuntu/parallel
ls
a.txt b.txt c.txt
{}
: 入力をそのまま加工しない
{}
は入力を何も加工せずそのまま変数として受け取る。
ls *.txt | parallel echo {}
a.txt
b.txt
c.txt
{.}
: 拡張子を取り除く
{.}
は入力をパスとして解釈して、パスから拡張子を取り除く。
ls *.txt | parallel echo {.}
a
b
c
注意点としては、{.}
はフルパスが与えられたときは特にファイル名だけをくり抜いたりはしない。
$ ls -d "$PWD/"* | parallel echo {.}
/home/ubuntu/parallel/a
/home/ubuntu/parallel/b
/home/ubuntu/parallel/c
{/}
: ファイル名だけを取り出す
{/}
は入力をパスとして解釈して、パスのうちファイル名部分を取り出す。
ls -d "$PWD/"* | parallel echo {/}
a.txt
b.txt
c.txt
{//}
: ファイルの属するディレクトリだけ取り出す
{//}
は入力をパスとして解釈して、パスのうちディレクトリ部分を取り出す。
ls -d "$PWD/"* | parallel echo {//}
/home/ubuntu/parallel
/home/ubuntu/parallel
/home/ubuntu/parallel
お役立ち引数
--dryrun
: 実際にコマンドは実行しない
--dryrun
を実行すると、parallel は変数を置換こそするがコマンドは実行しないで処理を進める。
例えば echo
を --dryrun
とともに用いると以下のようになる。
parallel --dryrun echo ::: 1 2 3
echo 1
echo 2
echo 3
echo
は実際には実行されず、変数部分だけ置き換えられるので echo 1
といった出力になる。
--bar
: プログレスバーを表示する
--bar
を parallel に与えると、実行の進捗をプログレスバーとして出力できる。
(以下の例は実際のターミナルで試すとプログレスバーが出てくる)
$ parallel --bar echo ::: 1 2 3
1
33% 1:2=0s 2
2
66% 2:1=0s 3
3
100% 3:0=0s 3
ユースケース
URL の一部を変数として受け取り、curl で並列 DL する
seq 10 | parallel --bar curl --silent https://httpbin.org/base64/{}
0% 0:10=0s 10
10% 1:9=0s 10
20% 2:8=0s 10
30% 3:7=0s 10
40% 4:6=0s 10
50% 5:5=0s 10
60% 6:4=0s 10
70% 7:3=0s 10
80% 8:2=0s 10
90% 9:1=0s 10
100% 10:0=1s 10
PNG を WebP にするが、コマンドの実行はしない
変換元はファイル名をそのまま受け取り、変換後は {.}
で拡張子を削っているのがポイント。
ls *.png | parallel --dryrun cwebp {} -o {.}.webp
cwebp a.png -o a.webp
cwebp b.png -o b.webp
cwebp c.png -o c.webp
補遺
Academic tradition requires ...
コマンドを実行すると、GNU parallel は parallel を用いて論文のデータ形を作るときに自分のことを引用してくれと言ってくる。10000ユーロ払えば引用しなくてもいいが、普通に引用したほうが得策であろう。
以下のコマンドで GNU parallel の言い分に同意できる = この通知を消せる。
parallel --citation
will cite
Discussion