もしBashスクリプトが実行に永遠にかかることにうんざりしているなら、このチュートリアルが役立ちます。よくあることですが、Bashスクリプトを並列で実行することができ、その結果を劇的に高速化することができます。どうやって?GNU Parallelユーティリティを使用します。また、Parallelとも呼ばれるこのユーティリティは、いくつかの便利なGNU Parallelの例と共に、Bashスクリプトを並列で実行します。
Parallelは、マルチスレッディングと呼ばれるコンセプトを介してBashスクリプトを並列で実行します。このユーティリティを使用すると、1つだけではなくCPUごとに異なるジョブを実行できるため、スクリプトの実行時間を短縮できます。
このチュートリアルでは、多くの優れたGNU Parallelの例を使ってマルチスレッディングBashスクリプトを学ぶことができます。
前提条件
このチュートリアルでは実演がたくさんあります。一緒に進めるつもりであれば、以下のものを用意してください:
- A Linux computer. Any distribution will work. The tutorial uses Ubuntu 20.04 running on Windows Subsystem for Linux (WSL).
- sudo権限を持つユーザーでログインしていること。
GNU Parallelのインストール
マルチスレッディングでBashスクリプトの実行を高速化するには、まずParallelをインストールする必要があります。では、ダウンロードしてインストールを始めましょう。
1. Bashターミナルを開きます。
2. wget
を実行してParallelパッケージをダウンロードします。以下のコマンドは、最新バージョン(parallel-latest
)を現在の作業ディレクトリにダウンロードします。
GNU Parallelの古いバージョンを使用したい場合は、公式のダウンロードサイトですべてのパッケージを見つけることができます。
3. 以下のtarコマンドを実行して、ダウンロードしたパッケージを展開します。
以下のコマンドでは、x
フラグを使用してアーカイブを展開し、j
を使用して.bz2
拡張子のアーカイブを対象とし、f
を使用してtarコマンドの入力としてファイルを受け入れます。sudo tar -xjf parallel-latest.tar.bz2
これで、最新リリースの年月日を含むparallel-という名前のディレクトリが作成されます。
4. パッケージアーカイブフォルダにcd
で移動します。このチュートリアルでは、パッケージアーカイブフォルダの名前はparallel-20210422として示されています。

5. 次に、以下のコマンドを実行してGNU Parallelバイナリをビルドしてインストールします。
今、Parallelが正しくインストールされたかどうかを確認してください。

初めてParallelを実行すると、
perl: warning:
というテキストが表示されるかもしれません。これらの警告メッセージは、Parallelが現在のロケールと言語設定を検出できないことを示しています。しかし、今のところはそれらの警告を心配しないでください。後でそれらの警告を修正する方法を学びます。
GNU Parallelの設定
今、Parallelがインストールされているので、すぐに使用できます!ただし、最初に始める前に、いくつかの細かい設定を行うことが重要です。
まだBashターミナルにいる場合は、GNU Parallelの学術研究許可に同意して、citation
パラメータの後にwill cite
を指定して、Parallelにこれを引用することを伝えてください。
GNUやそのメンテナーをサポートしたくない場合は、引用に同意することは必要ありません。
次に、以下のコードラインを実行して、次の環境変数を設定して、ロケールを変更してください。このようにしてロケールと言語の環境変数を設定することは必須ではありませんが、GNU Parallelは実行するたびにそれらをチェックします。
環境変数が存在しない場合、Parallelは前のセクションで見たように、その都度エラーを報告します。
このチュートリアルでは、あなたが英語を話す人であると想定しています。他の言語もサポートされています。

アドホックなシェルコマンドの実行
GNU Parallelを使い始めましょう!まずは、基本的な構文を学びます。構文に慣れたら、後で便利なGNU Parallelの例を見ていきましょう。
まずは、単純な例として、1から5までの数字を表示することから始めましょう。
1. Bashのターミナルで、以下のコマンドを実行してください。わくわくしませんか?Bashは、echoコマンドを使用して数字の1から5をターミナルに送信します。これらのコマンドをスクリプトに入れて実行すると、Bashはそれぞれのコマンドを順番に実行し、前のコマンドの終了を待ちます。
この例では、ほとんど時間を要しない5つのコマンドを実行しています。しかし、これらのコマンドが実際に役立つ処理を行うが実行に非常に長い時間を要する場合を想像してみてください。
次に、Parallelを使用してそれぞれのコマンドを同時に実行してみましょう。この例では、Parallelは:::
で指定されたechoコマンドを実行し、引数1
、2
、3
、4
、5
をそのコマンドに渡します。コロンの数は、Parallelに対してコマンドラインから入力を提供していることを示しています(パイプラインではなく)。
以下の例では、オプションを指定せずにParallelに単一のコマンドを渡しました。ここで、すべてのParallelの例と同様に、Parallelは異なるCPUコアを使用して各コマンドごとに新しいプロセスを開始しました。
すべてのParallelコマンドは、
parallel [オプション] <マルチスレッドのコマンド>
という構文に従います。
3. パイプラインからの入力を並列で受け取ることを示すには、以下のようにcount_file.txtというファイルを作成してください。 各数字は、echoコマンドに渡す引数を表します。
4. 今、cat
コマンドを実行して、そのファイルを読み取り、出力をParallelに渡します。 この例では、{}
はParallelに渡される各引数(1〜5)を表します。

BashとGNU Parallelの比較
現在、Parallelを使用することは、Bashコマンドを実行するやり方として複雑に見えるかもしれません。 しかし、あなたにとって本当の利点は時間の節約です。 Bashは1つのCPUコアで実行されますが、GNU Parallelは複数のコアで同時に実行されます。
1. 逐次的なBashコマンドとParallelの違いを示すために、次のコードを含むBashスクリプトtest.shを作成してください。 このスクリプトは、以前にcount_file.txtを作成したディレクトリに作成してください。
以下のBashスクリプトは、count_file.txtファイルを読み取り、1秒、2秒、3秒、4秒、5秒間スリープし、スリープの長さを端末にエコーして終了します。
2. 今度は、time
コマンドを使用してスクリプトを実行し、スクリプトの完了までにかかる時間を測定します。 15秒かかります。
3. 今度はtime
コマンドを使用して同じタスクを実行しますが、今回はParallelを使用します。
次のコマンドは同じタスクを実行しますが、最初のループが完了するのを待たずに、各CPUコアで1つずつ実行し、同時に実行できるだけ多くのタスクを開始します。

ドライランを知ろう!
これで、より実際のGNU Parallelの例に入る時が来ました。ただし、それを実際に実行せずに何が起こるかを確認したい場合は、--dryrun
フラグを使用します。
--dryrun
フラグは、思ったように動作しないコマンドを実行する前の最終的な健全性チェックとして機能します。残念ながら、システムに害を及ぼすコマンドを入力した場合、GNU Parallelが助けることは、それをより速く損なうことだけです!
GNU Parallelの例#1:Webからファイルをダウンロードする
このタスクでは、Web上のさまざまなURLからファイルのリストをダウンロードします。たとえば、これらのURLは保存したいWebページ、画像、またはFTPサーバーからのファイルのリストを表すことができます。
この例では、GNU ParallelのFTPサーバーからアーカイブパッケージのリスト(およびSIGファイル)をダウンロードします。
1. download_items.txtというファイルを作成し、公式のダウンロードサイトからいくつかのダウンロードリンクを取得し、ファイルに新しい行で区切って追加します。
PythonのBeautiful Soupライブラリを使用して、ダウンロードページからすべてのリンクをスクレイプすることで、時間を節約できます。
2. download_items.txtファイルからすべてのURLを読み取り、それらをParallelに渡します。Parallelはwget
を呼び出して、それぞれのURLを渡します。
並列コマンド内の
{}
は、入力文字列のプレースホルダーであることを忘れないでください!
3. おそらくGNU Parallelが一度に使用するスレッドの数を制御する必要があります。その場合は、--jobs
または-j
パラメータをコマンドに追加します。 --jobs
パラメータは、同時に実行されるスレッドの数を指定した数に制限します。
例えば、Parallelを一度に5つのURLをダウンロードするように制限する場合、コマンドは次のようになります:
上記のコマンドの
--jobs
パラメータは、コンピュータがその数のCPUを持っている限り、任意の数のファイルをダウンロードするために調整することができます。
4. --jobs
パラメータの効果を示すために、今度はジョブ数を調整し、time
コマンドを実行して各実行にかかる時間を計測します。
GNU Parallelの例2:アーカイブパッケージの展開
前の例からダウンロードしたすべてのアーカイブファイルを持っているので、これらをアンアーカイブする必要があります。
アーカイブパッケージと同じディレクトリにいる状態で、次のParallelコマンドを実行します。ワイルドカード(*
)の使用に注意してください。このディレクトリにはアーカイブパッケージとSIGファイルの両方が含まれているため、Parallelに対して.tar.bz2ファイルのみを処理するように指示する必要があります。
ボーナス!GNU Parallelを対話的に使用している場合(スクリプトではない場合)、タスクが実行されている間にParallelが進行状況バーを表示するために--bar
フラグを追加します。

--bar
flagGNU Parallelの例3:ファイルの削除
例1と例2を実行した場合、作業ディレクトリには多くのフォルダがあり、スペースを占有しています。したがって、これらのファイルを並列ですべて削除しましょう!
Parallelを使用して、parallel-で始まるすべてのフォルダーを削除するには、ls -d
を使用してすべてのフォルダーのリストを表示し、それぞれのフォルダーのパスをParallelに渡して、以下に示すように各フォルダーにrm -rf
を実行します。
--dryrun
フラグを覚えておいてください!
結論
これで、Bashを使用してタスクを自動化し、多くの時間を節約できます。その時間をどのように使うかはあなた次第です。時間を節約することが少し早く仕事を終えることであるか、別のATAブログの投稿を読むことであるかはあなた次第です。
今、環境で実行されているすべての長時間実行されるスクリプトを考えてみてください。それらのうち、どれをParallelで高速化できますか?
Source:
https://adamtheautomator.com/how-to-speed-up-bash-scripts-with-multithreading-and-gnu-parallel/