ジョブのフォアグラウンド実行とバックグラウンド実行
対話シェルでジョブ制御が有効な場合、シェルから起動したコマンド(ジョブ)は、通常はフォアグラウンド(画面の入出力を占有する状態)で実行されますが、時間のかかる処理を裏で実行させたい場合はバックグラウンドに回すことができます。
&によるバックグラウンド実行
コマンドの末尾に&を付けて実行すると、シェルはそのコマンドの終了を待たずに、すぐにプロンプトへ制御を戻します。
sleep 300 &&を付けて実行すると、シェルは[ジョブ番号] プロセスIDという形式の行を表示します(例: [1] 12345)。
jobsによる一覧表示
現在の対話シェルが管理しているジョブの一覧はjobsコマンドで確認できます。
| オプション | 内容 |
|---|---|
| (なし) | 実行中・停止中のジョブをジョブ番号付きで一覧表示する |
-l | ジョブ番号に加えてプロセスIDも表示する |
$ jobs
[1]+ Running sleep 300 &
[2]- Stopped vi memo.txtジョブ番号の直後に付く+は「カレントジョブ(fg・bgを引数なしで実行した際の対象)」、-は「1つ前のジョブ」を示します。
Ctrl+Zによる一時停止とbg・fgによる再開
フォアグラウンドで実行中のジョブに対してCtrl+Zを押すと、端末のラインディシプリンはフォアグラウンドのプロセスグループにSIGTSTPシグナルを送信しますSIGTSTPは、後述するSIGSTOPと違ってプロセス側で捕捉・無視ができる「ジョブ制御用の停止シグナル」です。捕捉・無視が一切できないSIGSTOPと混同しないよう注意してください。[1]。SIGTSTPが捕捉・無視されない通常の場合、ジョブは一時停止(サスペンド)します。一時停止したジョブはbgでバックグラウンド実行として再開でき、fgでは停止中のジョブまたは&でバックグラウンドに回した実行中のジョブをフォアグラウンドにできます。
| コマンド | 内容 |
|---|---|
fg | カレントジョブをフォアグラウンドで再開する |
fg %ジョブ番号 | 指定したジョブ番号をフォアグラウンドで再開する(例: fg %2) |
bg | カレントジョブをバックグラウンドで再開する(一時停止中のジョブを動かし始める) |
bg %ジョブ番号 | 指定したジョブ番号をバックグラウンドで再開する |
ジョブ番号は%1のように%を付けて指定するほか、%+(カレントジョブ)・%-(1つ前のジョブ)・%文字列(コマンド名がその文字列で始まるジョブ)という指定方法もあります。フォアグラウンドのジョブだけが端末からのキー入力やキーボード由来のシグナル(Ctrl+CによるSIGINT等)を受け取れる点が、フォアグラウンドとバックグラウンドの本質的な違いです。
ログアウト後も実行を継続させる方法
端末接続の切断や対話シェルの終了に伴い、シェルが管理するジョブはSIGHUPシグナル(ハングアップ)を受けることがあります。この挙動はシェルのジョブ制御設定等にも依存します。このため、時間のかかるバックグラウンド処理をログアウト後も継続させたい場合には、代表的に次の方法を使います。
nohup
nohupは、指定したコマンドをSIGHUPシグナルに対して免疫を持たせた(無視する)状態で実行するコマンドです。
nohup COMMAND [引数...]標準出力・標準エラー出力の扱いにも特徴があります。リダイレクト先を指定しなかった場合、標準出力が端末であれば、実行したディレクトリ内のnohup.outというファイルに追記され(書き込めない場合はホームディレクトリの$HOME/nohup.outに追記)、標準エラー出力が端末であれば標準出力にリダイレクトされます。ログアウト後も継続させたいバックグラウンド処理には、nohupと&を組み合わせるのが基本形です。
nohup ./long_batch.sh > batch.log 2>&1 &nohup自体はSIGHUPを無視させるだけで、コマンドをバックグラウンドで実行するわけではない点に注意してください。バックグラウンドで動かすには、上記のように別途&を付ける必要があります。
watch
watchは、指定したコマンドを一定間隔(既定では2秒)で繰り返し実行し、その出力を画面いっぱいに表示し続けるコマンドです。
| オプション | 内容 |
|---|---|
-n 秒数(--interval) | 実行間隔を指定する(既定は2秒) |
-d(--differences) | 直前の実行結果との差分をハイライト表示する |
watch -n 5 -d free -hwatch自体には、ログアウト後も処理を継続させる仕組みは組み込まれていませんマニュアルにも、バックグラウンド実行やデタッチ、セッションを超えた永続化についての記載はなく、qキーを押すか端末を閉じるまで、あくまでフォアグラウンドで動き続けるツールです。[2]。ログアウト後もwatchによる定期実行を対話的に続けたい場合は、後述のscreenまたはtmuxなど、持続する端末セッションの中で実行する必要があります。nohup watch -n 5 df -h &のような実行は、watchが端末画面を制御するプログラムであるため適切ではありません。非対話的に定期処理を継続したい場合は、watchではなく、実行対象のコマンドをシェルのループ等で繰り返し、その処理をnohupで実行します。「watchが単体でログアウト後の実行継続に対応している」という誤解をしないよう注意してください。
screen・tmux(端末多重化ソフトウェア)
screen・tmuxは、いずれも複数の仮想的な端末であるウィンドウやペインをセッション内で管理し、それらを丸ごと「デタッチ(切り離し)」してバックグラウンドに残したまま、後から別の接続で「アタッチ(再接続)」できるようにする、端末多重化ソフトウェアです。nohupと異なり、コマンド単体ではなくシェルセッション全体を丸ごと持続させられる点が特徴です。
screenの基本操作
| コマンド・キー操作 | 内容 |
|---|---|
screenまたはscreen -S 名前 | 新しいセッションを開始する(-Sで名前を付けられる) |
Ctrl+a に続けて d | 現在のセッションをデタッチする(処理は継続したまま端末から切り離す) |
screen -ls | 現在のセッション一覧を表示する |
screen -r 名前(またはscreen -r セッションID) | 指定したセッションに再アタッチする |
screen -S build
(この中でビルド処理を実行し、Ctrl+a d でデタッチしてログアウトしても継続)
screen -r buildtmuxの基本操作
| コマンド・キー操作 | 内容 |
|---|---|
tmuxまたはtmux new -s 名前 | 新しいセッションを開始する(-sで名前を付けられる) |
Ctrl+b に続けて d | 現在のセッションをデタッチする |
tmux ls | 現在のセッション一覧を表示する |
tmux attach -t 名前 | 指定したセッションに再アタッチする |
tmux new -s build
(この中でビルド処理を実行し、Ctrl+b d でデタッチしてログアウトしても継続)
tmux attach -t buildscreenとtmuxは設計思想が近く、どちらもデタッチ・アタッチという考え方は共通していますが、キー操作の既定値(プレフィックスキーがCtrl+aかCtrl+bか)や、ウィンドウ・ペインの分割操作の詳細は異なります。
活動中のプロセスの監視
ps(プロセスの一覧をスナップショットとして表示)
psは、実行時点におけるプロセスの状態を一覧表示するコマンドです。
オプションには、UNIX形式(ハイフン付き)とBSD形式(ハイフンなし)があります。
| オプション(例) | 内容 |
|---|---|
-e | 全ユーザーの全プロセスを表示する |
-f | UID、PPID、開始時刻などを含むフル形式で表示する |
-u ユーザー名 | 指定したユーザーのプロセスを表示する |
u | CPU使用率やメモリ使用量を含むBSD形式で表示する |
-C コマンド名 | 指定したコマンド名のプロセスを表示する |
-ef | UNIX形式で全プロセスを詳しく表示する |
aux | 端末を持たないものを含め、全ユーザーのプロセスをBSD形式で表示する |
実行結果の見方
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 168000 12000 ? Ss 09:00 0:02 /sbin/init| 項目 | 意味 |
|---|---|
USER / PID | 実行ユーザー/プロセスID |
%CPU / %MEM | CPU使用率/物理メモリ使用率 |
VSZ / RSS | 仮想メモリサイズ/使用中の物理メモリサイズ |
TTY | 制御端末。?は制御端末を持たないことを表す |
STAT | プロセスの状態 |
START / TIME | 開始時刻/使用したCPU時間の合計 |
COMMAND | 実行中のコマンドと引数 |
主なSTATは、R(実行中)、S(割り込み可能な待機)、D(割り込み不可の待機)、T(停止)、Z(ゾンビ)です。 ps -efでは、親プロセスのIDを表すPPIDなども確認できます。
ps -ef | grep sshd
ps aux --sort=-%cpu | headpsは実行した瞬間の状態を1回だけ表示します。継続的な監視にはtopやwatchを使用します。
top(動的なリアルタイム監視)
topは、CPU使用率やメモリ使用状況、プロセスごとの資源使用量を、一定間隔で自動的に更新しながら対話的に表示するコマンドです。画面の上部には、稼働時間・ロードアベレージ・タスク数(実行中/スリープ/停止/ゾンビ)・CPU使用率の内訳・メモリ使用量が表示され、下部には個々のプロセスの一覧が表示されます。
| キー操作・オプション | 内容 |
|---|---|
q | 終了する |
k | 対象プロセスのPIDと送信するシグナルを指定して、シグナルを送信する(既定はSIGTERM) |
r | 対象プロセスのPIDと新しい優先度(nice値)を指定して、renice(優先度変更)を行う |
M | メモリ使用率(%MEM)順に並べ替える |
P | CPU使用率(%CPU)順に並べ替える |
d(起動時は-d 秒数) | 更新間隔を変更する |
top -d 2pstree(親子関係を木構造で表示)
pstreeは、プロセスの親子関係をツリー(階層)形式で表示するコマンドです。
| オプション | 内容 |
|---|---|
-p | 各プロセスのPIDを表示する |
-u | 実行ユーザーが変わる箇所にユーザー名を表示する |
-a | 各プロセスのコマンドライン引数も表示する |
-n | 同じ階層の兄弟プロセスをPID順に並べ替える |
pstree -ppstreeは既定ではPIDを一切表示しません。 PIDを確認したい場合は必ず-pオプションを付ける必要があり、これを付けずに実行したpstreeの出力からPIDを探そうとするのは典型的な誤りです。
uptime・free(システム全体の状態を一言で確認)
uptimeは、現在時刻・システムの連続稼働時間・ログイン中のユーザー数・過去1分/5分/15分間のロードアベレージを1行で表示するコマンドです。ロードアベレージは「実行可能状態、または割り込み不可能な待機状態にあるプロセス数の平均」であり、CPUのコア数を考慮しない値である点に注意してください。ロードアベレージはCPU使用率そのものではありませんが、CPU負荷を判断する目安としてコア数と比較できます。例えば、CPU負荷が実行可能状態のプロセスだけによる場合、ロードアベレージが1.0ならシングルコアでは1コア分、4コアでは全体の4分の1程度のCPU処理能力が使われている目安になります。
| オプション | 内容 |
|---|---|
-p | 稼働時間を「up 3 days, 2 hours」のような読みやすい形式で表示する |
-s | システムが起動した日時をyyyy-mm-dd HH:MM:SS形式で表示する |
freeは、物理メモリ・スワップ領域の使用状況を表示するコマンドです。
| オプション | 内容 |
|---|---|
-h | 各数値を読みやすい単位(K/M/G等)に自動変換して表示する |
-m・-g | 単位をそれぞれメビバイト・ギビバイトに固定して表示する |
-s 秒数 | 指定した間隔で繰り返し表示する |
-t | 合計値の行を追加表示する |
主な列は、総容量を示すtotal、使用中のused、未使用のfree、tmpfs等で使われるshared、バッファ・キャッシュ用のbuff/cache、そして新規プロセスの起動にどれだけ余裕があるかを示すavailableです。「free列(未使用メモリ)が少ない=メモリが逼迫している」と短絡的に判断せず、キャッシュ等を差し引いたavailable列を確認する習慣が重要ですLinuxカーネルは、空いているメモリをできるだけバッファ・キャッシュとして活用する設計になっているため、free列の値だけでは実際に利用可能な余裕を正しく判断できません。[3]。
プロセス群の選択と並べ替え表示
pgrep(プロセス名等からPIDを検索)
pgrepは、プロセス名やその他の条件に一致するプロセスのPIDを検索して表示するコマンドです。psの出力をgrepで絞り込む処理を1つのコマンドで行えます。
| オプション | 内容 |
|---|---|
-u ユーザー名 | 指定したユーザーが所有するプロセスに絞り込む |
-l | PIDに加えてプロセス名も表示する |
-f | プロセス名だけでなく、コマンドライン全体を対象に照合する |
-x | プロセス名(またはコマンドライン全体)の完全一致のみを対象にする |
-c | 一致したプロセスの件数のみを表示する |
pgrep -u root updatedb
pgrep -f "python.*worker.py"例えば「rootユーザーが実行しているupdatedbプロセスのPIDを調べる」場合、pgrep -u root updatedbのほか、ps -efやps u -C updatedbの出力から目視で確認する方法もあります。一方、前述のpstreeは-pを付けない限りPIDを表示しないため、PIDを調べる目的では単体では使えません。
プロセスへのシグナル送信
シグナルの基礎
プロセスへ送るシグナルには、それぞれ名前と番号が割り当てられています。番号は原則としてアーキテクチャ間で共通ですが、一部のシグナルは番号がアーキテクチャによって異なります。
| シグナル名 | 番号(x86/x86_64環境) | 内容 |
|---|---|---|
| SIGHUP | 1 | ハングアップ(端末切断、または設定再読み込みの合図として使う場合もある) |
| SIGINT | 2 | 割り込み(Ctrl+C相当) |
| SIGQUIT | 3 | 終了(コアダンプを伴う) |
| SIGKILL | 9 | 強制終了(捕捉・無視・ブロックが一切できない) |
| SIGTERM | 15 | 終了要求(既定のシグナル。プロセスは捕捉して終了処理を行える) |
| SIGCONT | 18 | 一時停止中のプロセスを再開する |
| SIGSTOP | 19 | 一時停止させる(SIGKILL同様、捕捉・無視ができない) |
| SIGTSTP | 20 | 一時停止させる(Ctrl+Z相当。SIGSTOPと異なりプロセス側で捕捉・無視が可能) |
SIGCONT・SIGSTOP・SIGTSTP等の番号はAlpha・SPARC・MIPSといった一部のアーキテクチャでは異なる値になりますが、SIGHUP・SIGINT・SIGQUIT・SIGKILL・SIGTERMの番号(1・2・3・9・15)は主要なアーキテクチャ間で共通です本記事の番号は、一般的なx86/x86_64環境(signal(7)マニュアルページに基づく)のものです。試験対策としては、まず「番号よりもシグナル名で指定する方が確実」という考え方を押さえた上で、SIGKILL(9)・SIGTERM(15)といった頻出の番号を覚えておくとよいでしょう。[4]。
kill(PIDを指定してシグナルを送信)
killは、指定したPIDのプロセスにシグナルを送信するコマンドです。名前に反して、既定では「強制終了」ではなく、終了処理を行えるSIGTERMを送信します。
| 書式 | 内容 |
|---|---|
kill PID | 対象PIDにSIGTERM(既定)を送信する |
kill -SIGNAL PID・kill -シグナル名 PID | 番号または名前でシグナルを指定する(例: kill -9 PID、kill -SIGKILL PID) |
kill -l | 利用可能なシグナルの一覧を表示する |
kill -TERM 12345
kill -9 12345killは、まずSIGTERMでプロセスに終了処理を行う機会を与え、それでも終了しない場合に限ってSIGKILLを使う、という順序が一般的な運用です。SIGKILLはプロセス側で後処理(一時ファイルの削除等)を行う余地なく即座に終了させてしまうため、多用は推奨されません。
pkill・killall(名前や条件を指定してシグナルを送信)
pkillはpgrepと対になるコマンドで、PIDではなくプロセス名や条件を指定して、一致した全プロセスにシグナルを送信します。オプションの意味はpgrepとほぼ共通です(-u・-f・-x等)。シグナルの指定は-シグナル名または--signal シグナル名という書式で行います。
pkill -f "python.*worker.py"
pkill -u alice firefoxkillallも同様にプロセス名を指定してシグナルを送信するコマンドですが、pkillとは実装も挙動も異なる別のコマンドです。killallでプロセスにシグナルを送るには、少なくとも1つのプロセス名(引数)を指定する必要があります。一部のUNIX系OS(Solaris等)のkillallには引数なしで全プロセスを終了させる挙動のものが存在しますが、Linuxのkillall(psmiscパッケージ)では引数なしで全プロセスを終了させることはありません。なお、killall -lのように情報を表示するオプションはプロセス名なしで実行できます。異なるOS間で挙動が違う点に注意してください。[5]。
| オプション | 内容 |
|---|---|
-i | 終了させる前に対話的に確認する |
-e | 長いプロセス名について、完全名を確認できないプロセスを対象から除外する |
-r | 正規表現(POSIX拡張正規表現)でプロセス名を指定する |
-u ユーザー名 | 指定したユーザーが所有するプロセスに絞り込む |
killall -i firefox
killall -u alice --signal TERM firefoxkillallは既定では指定したプロセス名に一致するプロセスを対象にしますが、プロセス名がカーネル側の制限により15文字に切り詰められて記録される場合があり、長いプロセス名では先頭15文字が同じ別のプロセスまで一致する可能性があります。長いプロセス名で先頭15文字だけの一致を避けたい場合は-eオプションを使ってください。ただし、完全名を確認できないプロセスは-eによってスキップされます。
補足
- SIGTSTPは、後述するSIGSTOPと違ってプロセス側で捕捉・無視ができる「ジョブ制御用の停止シグナル」です。捕捉・無視が一切できないSIGSTOPと混同しないよう注意してください。 ↩
- マニュアルにも、バックグラウンド実行やデタッチ、セッションを超えた永続化についての記載はなく、
qキーを押すか端末を閉じるまで、あくまでフォアグラウンドで動き続けるツールです。 ↩ - Linuxカーネルは、空いているメモリをできるだけバッファ・キャッシュとして活用する設計になっているため、
free列の値だけでは実際に利用可能な余裕を正しく判断できません。 ↩ - 本記事の番号は、一般的なx86/x86_64環境(
signal(7)マニュアルページに基づく)のものです。試験対策としては、まず「番号よりもシグナル名で指定する方が確実」という考え方を押さえた上で、SIGKILL(9)・SIGTERM(15)といった頻出の番号を覚えておくとよいでしょう。 ↩ - 一部のUNIX系OS(Solaris等)の
killallには引数なしで全プロセスを終了させる挙動のものが存在しますが、Linuxのkillall(psmiscパッケージ)では引数なしで全プロセスを終了させることはありません。なお、killall -lのように情報を表示するオプションはプロセス名なしで実行できます。異なるOS間で挙動が違う点に注意してください。 ↩