「xargs -P で並列化しているが、ジョブ数の上限制御や失敗したジョブの特定が難しい——」
こういった経験をした方は多いはずです。Linuxの標準機能(& + wait、xargs -P)でも並列処理は実現できますが、本番運用に耐える設計——ジョブ数制御・失敗時の自動停止・実行ログの保存——を組み込もうとすると途端に複雑になります。
この記事では、RHEL 9系/Ubuntu 24.04 LTSを想定環境として、GNU parallelコマンドの基本構文から本番向け設計パターンまでを解説します。GNU parallelは標準リポジトリからインストールできる外部ツールで、シェルスクリプトの並列処理を宣言的かつ堅牢に設計できます。
この記事のポイント
・GNU parallelは--jobsでジョブ数を制御し、xargs -Pより直感的に並列数を管理できる
・--halt now,fail=1で1件でも失敗したら全ジョブを即停止できる
・--joblongで各ジョブの終了コード・実行時間をCSV形式でファイルに保存できる
・--will-citeで確認プロンプトを抑制してcronから無人実行できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
GNU parallelとは — &+waitやxargsとの違い
GNU parallelはシェルコマンドを複数プロセスで並列実行するためのユーティリティです。2010年代から継続開発されており、RHEL 9・Ubuntu 24.04 LTSの標準リポジトリからインストールできます。まず、既存の並列処理手法との差を整理しておきます。
| 手法 | ジョブ数制限 | エラーで全停止 | 実行ログ | 出力混在対策 |
|---|---|---|---|---|
| & + wait | 手動実装が必要 | 手動実装が必要 | なし | なし(混在する) |
| xargs -P | -P N で指定 | 不可 | なし | 混在する |
| GNU parallel | --jobs N/% で指定 | --halt で制御可 | --joblog で保存 | --line-buffer/--group |
GNU parallelのインストールと基本構文
1. インストール方法
# RHEL 9 / CentOS Stream 9 / Rocky Linux 9 $ sudo dnf install parallel # Ubuntu 24.04 LTS / Debian $ sudo apt install parallel # バージョン確認 $ parallel --version # 出力例(環境により異なります) # GNU parallel 20231122
2. 基本構文
最もシンプルな形はparallel コマンド ::: 引数リスト です。:::(3つのコロン)が「このあとに引数を列挙する」という区切りです。# 基本構文: parallel [オプション] コマンド ::: 引数1 引数2 ... parallel echo ::: A B C # 出力例(順不同・環境により異なります) # A # B # C # {}(中括弧)が引数の置換文字 parallel echo "Processing: {}" ::: A B C # Processing: A # Processing: B # Processing: C
・{}:引数全体(ファイルパスならフルパス)
・{.}:拡張子を除いた部分(
/var/log/app.log → /var/log/app)・{/}:ディレクトリ部分を除いたファイル名(
app.log)・{//}:ディレクトリ部分のみ(
/var/log)・{#}:ジョブの通し番号(1, 2, 3 …)
本番向け設計パターン4選
1. --jobsでジョブ数を制御する
デフォルトはCPUコア数と同じ数のジョブを起動します。サーバーに負荷をかけたくない場合は明示的に制限します。# 同時に4ジョブまで実行 parallel --jobs 4 'gzip -9 {}' ::: /var/log/app/2024-*.log # CPUコア数の50%以下に制限(例: 8コアなら最大4ジョブ) parallel --jobs 50% 'gzip -9 {}' ::: /var/log/app/2024-*.log # ファイルから引数リストを読み込む(:::: でファイル指定) find /var/log/app -name "*.log" -mtime +7 > /tmp/targets.txt parallel --jobs 4 'gzip -9 {}' :::: /tmp/targets.txt
2. --haltでエラー時に全ジョブを即停止する
バックアップ処理など「1件でも失敗したら全体を止めたい」ケースで有効です。# --halt now,fail=1: 1件でも失敗したら実行中のジョブも即SIGTERM parallel --halt now,fail=1 'rsync -a {} backup01:/backup/' ::: /data/db /data/files /data/media # --halt soon,fail=1: 実行中のジョブは最後まで待ってから停止(より安全) parallel --halt soon,fail=1 'rsync -a {} backup01:/backup/' ::: /data/db /data/files /data/media
nowとsoonの選択は処理内容によります。データベースダンプなど途中で中断すると壊れる処理はsoonを使いましょう。【注意】
--halt now,fail=1は実行中のジョブをSIGTERMで強制停止します。gzip圧縮中のファイルや書き込み途中のバックアップファイルが破損するリスクがあります。ファイル書き込みを伴う処理にはsoonを使うか、処理後に整合性チェックを入れてください。3. --joblongで実行ログを保存する
本番スクリプトでは後から障害調査できるよう、各ジョブの実行結果をログに残すことが重要です。JOBLOG="/var/log/parallel-compress-$(date +%Y%m%d).log" parallel --jobs 4 --halt soon,fail=1 --joblog "$JOBLOG" 'gzip -9 {}' ::: /var/log/app/2024-*.log # ログの形式(タブ区切り) # Seq Host Starttime JobRuntime Send Receive Exitval Signal Command # 1 : 1700000000.000 1.234 0 0 0 0 gzip -9 /var/log/app/2024-01-01.log # 失敗ジョブだけを抽出(Exitval != 0) awk 'NR>1 && $7 != 0 { print $9, "exit:", $7 }' "$JOBLOG"
4. --will-citeでcronから無人実行する
GNU parallelは初回起動時に「論文を引用してください」という確認プロンプトを表示します。これがcronで詰まる原因になるため、--will-citeで抑制します。# NG: cronから実行すると確認プロンプトで止まる parallel --jobs 4 'gzip {}' ::: *.log # OK: --will-cite でプロンプトを抑制 parallel --will-cite --jobs 4 'gzip {}' ::: *.log # または: ~/.parallel/will-cite ファイルを作成しておく(恒久設定) mkdir -p ~/.parallel touch ~/.parallel/will-cite
実践スクリプト — ログファイルの一括圧縮バックアップ
シェルスクリプトをより体系的に設計したい方は、シェルスクリプト設計の実践入門もあわせてご覧ください。ここまでのオプションを組み合わせた実践スクリプトを示します。
#!/bin/bash set -euo pipefail LOG_DIR="/var/log/app" ARCHIVE_DIR="/backup/logs" JOBLOG="/var/log/parallel-compress-$(date +%Y%m%d).log" MAX_JOBS=4 DAYS_OLD=7 # 7日以上前のログを圧縮対象リストに追加 find "$LOG_DIR" -name "*.log" -mtime +"$DAYS_OLD" > /tmp/compress_targets.txt # 対象ファイルが0件なら終了 if [ ! -s /tmp/compress_targets.txt ]; then echo "対象ファイルなし" exit 0 fi echo "圧縮対象: $(wc -l < /tmp/compress_targets.txt) 件" # GNU parallel で並列圧縮 + アーカイブディレクトリへ移動 parallel --will-cite --jobs "$MAX_JOBS" --halt soon,fail=1 --joblog "$JOBLOG" --progress 'gzip -9 {} && mv {}.gz '"$ARCHIVE_DIR"'/' :::: /tmp/compress_targets.txt echo "完了。ログ: $JOBLOG"
・対象が0件なら早期終了(無駄な並列起動を防ぐ)
・
--halt soon,fail=1でgzip失敗時は全体を停止(中途半端な状態を残さない)・
--joblogで各ファイルの処理結果を記録(後から失敗ファイルを特定できる)・
set -euo pipefailで変数ミスや予期しないエラーを早期検知トラブルシュート
「GNU parallel will be cited...」のメッセージが出て止まる
cronから実行したとき標準エラーに次のメッセージが出て、処理が進まなくなる場合があります。# このメッセージが標準エラーに出て確認を求められる # Academic tradition requires you to cite works you base your activities on. # 対処法1: スクリプトに --will-cite を付ける(推奨) parallel --will-cite --jobs 4 ... # 対処法2: ~/.parallel/will-cite ファイルを作成(恒久設定) mkdir -p ~/.parallel && touch ~/.parallel/will-cite
ジョブの出力が混在して読みにくい
複数ジョブが同時に標準出力に書き込むと行が混在します。# --line-buffer: 1行単位でバッファリング。行の混在を最小化 parallel --line-buffer --jobs 4 'echo "job {}: done"' ::: 1 2 3 4 # --group(デフォルト動作): ジョブが完了するまで出力を保持して一括出力 # 出力は混在しないが、ジョブが長時間かかると表示が遅延する parallel --group --jobs 4 'long-running-cmd {}' ::: A B C
GNU parallelとxargs -Pの使い分け指針
| 状況 | 推奨 |
|---|---|
| 標準インストール環境のみで動かしたい | xargs -P(外部ツール不要) |
| ジョブ数制御・エラー停止・実行ログが必要 | GNU parallel |
| SSH経由で複数サーバーに並列実行 | GNU parallel(--sshloginfile) |
| 大量のstdinをパイプで並列処理 | GNU parallel(--pipe) |
本記事のまとめ
| やりたいこと | コマンド |
|---|---|
| ジョブ数を4つに制限して並列実行 | parallel --jobs 4 cmd ::: args |
| 1件失敗したら全ジョブを即停止 | parallel --halt now,fail=1 cmd ::: args |
| 各ジョブの実行ログをファイルに保存 | parallel --joblog /tmp/log.csv cmd ::: args |
| 進捗をリアルタイム表示しながら実行 | parallel --progress cmd ::: args |
| cron実行時の確認プロンプトを抑制 | parallel --will-cite cmd ::: args |
| 出力の行混在を防いで読みやすくする | parallel --line-buffer cmd ::: args |
--will-citeを忘れずに付け、--joblogで障害調査の手がかりを残す設計を心がけてください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
シェルスクリプトの設計から本番自動化まで、ハンズオンで習得できる実践コースを公開しています。詳細はこちら >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:シェルスクリプトのログ設計パターン|ログレベル関数・タイムスタンプ付与・ファイルとコンソール分岐を実装する方法
- この記事の属するカテゴリ:シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます