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

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

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

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

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

code
ls ./not_exist &
echo "ステータス=$? プロセスID=$!"
stdout
ステータス=0 プロセスID=3965
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]-  3982 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  3983 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]-  4016 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  4018 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]-  4045 Running                 { sleep 0.1; echo ' task1) done'; } &
[2]+  4046 Running                 { sleep 0.2; echo ' task2) done'; } &
main) wait pid=4045
 task1) done
main) wait pid=4045 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]+  4181 Running                 { sleep 0.1; echo ' task) done'; exit 99; } &
main) wait pid=4181
 task) done
main) wait pid=4181 done
main) wait pid=4181 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]-  4221 Running                 { sleep 0.1; echo ' task1) done'; exit 91; } &
[2]+  4222 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]-  4266 Running                 { sleep 0.1; echo ' job1) done'; exit 1; } &
[2]+  4267 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]+  4287 Running                 { sleep 1; echo ' task) done'; } &
main) task kill 4287
main) task killed status=0
main) task wait 4287 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