はじめに
スクリプトを実行する際、コマンドを順番に実行するだけでなく、バックグラウンドでの並列実行や、中断時の適切な処理が必要になることがあります。
これらを制御するのが「プロセス制御」と「シグナルハンドリング」です。
1. trap コマンドによるシグナルハンドリング
スクリプト実行中に Ctrl+C (SIGINT) が押された場合や、スクリプトが終了する際に、特定の処理(一時ファイルの削除など)を実行させることができます。
終了時のクリーンアップ (EXIT)
スクリプトが終了する際(正常終了、エラー終了問わず)に必ず実行したい処理がある場合、EXIT シグナルをトラップします。
temp_file=$(mktemp)
cleanup() {
echo "Cleaning up..."
rm -f "$temp_file"
}
# スクリプト終了時に必ず cleanup を実行
trap cleanup EXIT
echo "Working with $temp_file..."
# 処理...
この記述をしておくことで、途中でエラーが発生して終了した場合でも、一時ファイルが残ってしまうのを防ぐことができます。
2. バックグラウンド実行と wait
処理に時間がかかるコマンドをバックグラウンドで実行し、並列処理を行うことで、スクリプト全体の実行時間を短縮できます。
基本的な並列実行
コマンドの末尾に & を付けることで、そのコマンドはバックグラウンドで実行されます。
wait コマンドを使うことで、バックグラウンドプロセスの完了を待つことができます。
echo "Starting tasks..."
# 3つの処理を並列に実行
sleep 5 &
sleep 5 &
sleep 5 &
# 全てのバックグラウンドプロセスの完了を待つ
wait
echo "All tasks completed."
直列に実行すると15秒かかりますが、並列に実行することで、約5秒で完了します。
3. プロセス置換 <(cmd)
BashやZshでは、コマンドの出力をファイルのように扱う「プロセス置換」が利用できます。
一時ファイルを作成せずに、コマンドの結果を別のコマンドの引数として渡すことができます。
diff でコマンド結果を直接比較
# ローカルとリモートのディレクトリ構成を比較
diff <(ls -R /local/dir) <(ssh remote ls -R /remote/dir)
この構文により、ls コマンドの出力がファイルと同様に diff コマンドに渡されます。
4. サブシェル ()
括弧 () で囲まれたコマンド群は、現在のシェルとは別のプロセス(サブシェル)で実行されます。
サブシェル内での変数の変更やディレクトリ移動(cd)は、元のシェルには影響を与えません。
current_dir=$(pwd)
(
cd /tmp
echo "In subshell: $(pwd)"
# ここでの作業は親シェルに影響しない
)
echo "Back in parent: $(pwd)"
# -> 元のディレクトリのまま
一時的にディレクトリを移動して作業したい場合などに便利です。
次回
次回は 「デバッグとシェルオプション」 について解説します。