バックグラウンドで処理を実行する

制御演算子「&」を使用してバックグラウンド実行する

コマンドの後ろに制御演算子「&」をつけて実行した場合、シェルはそのコマンドをサブシェル内でバックグラウンドで実行します。

code
sleep 0.1 &
echo "ステータス=$? プロセスID=$!"
stdout
ステータス=0 プロセスID=3764

「$!」は最後に実行されたバックグラウンドコマンドのプロセスIDに置換されます。コマンドをバックグラウンドで実行した場合、シェルはコマンドの終了を待たずに終了ステータス 0 を返却します。

code
ls ./not_exist &
echo "ステータス=$? プロセスID=$!"
stdout
ステータス=0 プロセスID=3922
stderr
cannot access './not_exist': No such file or directory

バックグラウンドで実行処理の終了を待つ

バックグラウンドで実行されたコマンドは非同期で実行されるため、呼び出し元の処理はバックグラウンドで実行した処理の終了を待ちません。

code
# バックグラウンドで実行した処理の done が出力される前に
# メイン処理の done が出力される
{ sleep 0.1; echo ' task1) done'; } &
{ sleep 0.1; echo ' task2) done'; } &
jobs -l
echo 'main) done'
stdout
[1]-  3958 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  3959 Running                 { sleep 0.1; echo ' task2) done'; } &
main) done
 task1) done
 task2) done

バックグラウンドで実行した処理の終了を待つには wait コマンドを使用します。

code
{ sleep 0.1; echo ' task1) done'; } &
{ sleep 0.1; echo ' task2) done'; } &
jobs -l
echo "main) wait"
wait
echo "main) wait done status=$?"
jobs -l
echo 'main) done'
stdout
[1]-  4002 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  4003 Running                 { sleep 0.1; echo ' task2) done'; } &
main) wait
 task1) done
 task2) done
main) wait done status=0
main) done

wait コマンドには終了を待機する処理のプロセスIDまたはジョブIDを指定することができます。指定しない場合はすべてのバックグラウンド処理の終了を待ちます。

code
{ sleep 0.1; echo ' task1) done'; } &
task1=$!
{ sleep 0.2; echo ' task2) done'; } &
jobs -l
echo "main) wait pid=${task1}"
wait "${task1}"
echo "main) wait pid=${task1} done status=$?"
echo 'main) done'
stdout
[1]-  4035 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  4036 Running                 { sleep 0.2; echo ' task2) done'; } &
main) wait pid=4035
 task1) done
main) wait pid=4035 done status=0
main) done
 task2) done

wait コマンドの終了ステータスについて

wait コマンドに終了を待機する処理のプロセスIDやジョブIDを指定して実行した場合の終了ステータスは終了を待機した処理の終了ステータスになります。

code
{ sleep 0.1; echo ' task) done'; exit 99; } &
jobs -l
echo "main) wait pid=$!"
wait $!
echo "main) wait pid=$! done"
jobs -l
echo "main) wait pid=$! status=$?"
echo 'main) done'
jobs -l
stdout
[1]+  4117 Running                 { sleep 0.1; echo ' task) done'; exit 99; } &
main) wait pid=4117
 task) done
main) wait pid=4117 done
main) wait pid=4117 status=0
main) done

引数を指定せずに wait コマンドでバックグラウンドプロセスの終了を待機した場合、wait コマンドの終了ステータスは 0 になります。

code
{ sleep 0.1; echo ' task1) done'; exit 91; } &
{ sleep 0.2; echo ' task2) done'; exit 92; } &
jobs -l
echo "main) wait"
wait
echo "main) wait status=$?"
echo 'main) done'
jobs -l
stdout
[1]-  4200 Running                 { sleep 0.1; echo ' task1) done'; exit 91; } &
[2]+  4201 Running                 { sleep 0.2; echo ' task2) done'; exit 92; } &
main) wait
 task1) done
 task2) done
main) wait status=0
main) done

wait コマンドに存在しないプロセスIDやジョブIDを指定した場合、wait コマンドの終了ステータスは 127 になります。

code
wait 9999
echo "wait done status=$?"
stdout
wait done status=127
stderr
line 1: wait: pid 9999 is not a child of this shell

wait コマンドにジョブIDを指定する場合は「%ジョブ番号」の形で指定します。

code
{ sleep 0.1; echo ' job1) done'; exit 1; } &
{ sleep 0.2; echo ' job2) done'; exit 2; } &
jobs -l
wait %1
echo "main) wait job1 status=$?"
wait %2
echo "main) wait job2 status=$?"
jobs -l
echo 'main) done'
stdout
[1]-  4246 Running                 { sleep 0.1; echo ' job1) done'; exit 1; } &
[2]+  4247 Running                 { sleep 0.2; echo ' job2) done'; exit 2; } &
 job1) done
main) wait job1 status=1
 job2) done
main) wait job2 status=2
main) done

バックグラウンドプロセスを強制終了させる

バックグラウンド処理は kill コマンドで強制終了させることができます。

code
{ sleep 1; echo ' task) done'; } &
jobs -l
echo "main) task kill $!"
kill $!
echo "main) task killed status=$?"
wait $!
echo "main) task wait $! status=$?"
jobs -l
stdout
[1]+  4277 Running                 { sleep 1; echo ' task) done'; } &
main) task kill 4277
main) task killed status=0
main) task wait 4277 status=143

強制終了させたバックグラウンド処理の終了ステータスを wait コマンドで取得したところ 143 でした。終了ステータスが 143 なので SIGTERM (143 - 128 = 15) を送られて終了していることが確認できました。

code
kill -l
stdout
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX