ps –forest
psに--forestを付けると、プロセスの一覧を親子関係のツリーとして表示する。ps -efの情報量を保ったまま、どのプロセスがどこから起動されたかを確認できる。
$ ps -ef --forest
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:58 ? 00:00:00 /sbin/init
root 24 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-journald
systemd+ 73 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-resolved
message+ 82 1 0 12:58 ? 00:00:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 87 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-logind
root 93 1 0 12:58 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 94 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 95 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 96 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 97 93 0 12:58 ? 00:00:00 \_ nginx: worker process
syslog 99 1 0 12:58 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE
root 175 1 0 12:59 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 383 175 0 13:01 ? 00:00:00 \_ sshd: alice [priv]
alice 394 383 0 13:01 ? 00:00:00 | \_ sshd: alice@notty
alice 395 394 0 13:01 ? 00:00:00 | \_ sh -c top -b -d 60
alice 396 395 0 13:01 ? 00:00:00 | \_ top -b -d 60
root 611 175 0 13:04 ? 00:00:00 \_ sshd: alice [priv]
alice 628 611 0 13:04 ? 00:00:00 \_ sshd: alice@pts/0
alice 629 628 0 13:04 pts/0 00:00:00 \_ sh -c bash /home/alice/report.sh > /home/alice/report.log 2>&1
alice 630 629 0 13:04 pts/0 00:00:00 \_ bash /home/alice/report.sh
alice 631 630 0 13:04 pts/0 00:00:00 \_ ps -ef --forest
alice 179 1 0 12:59 ? 00:00:00 /bin/bash -c sleep 3000 & sleep 3000 & wait
alice 181 179 0 12:59 ? 00:00:00 \_ sleep 3000
alice 182 179 0 12:59 ? 00:00:00 \_ sleep 3000
alice 191 1 0 12:59 ? 00:00:00 /usr/lib/systemd/systemd --user
alice 192 191 0 12:59 ? 00:00:00 \_ (sd-pam)
alice 382 1 0 13:01 ? 00:00:00 /usr/bin/ssh -n localhost top -b -d 60
alice 610 1 21 13:04 ? 00:00:00 /usr/bin/ssh -tt localhost bash /home/alice/report.sh > /home/alice/report.log 2>&1
ツリーはコマンド列に描かれる。\_が子プロセスを表す。|は同じ親を持つ兄弟がさらに下へ続く場合に引かれる縦線である。上の例ではsshdからsh、shからpsへとつながっている。SSHでログインしてreport.shを実行し、report.shの中でpsが動いていると読み取れる。
--forestはprocps-ngのpsが持つオプションで、DebianやUbuntu、RHEL系のディストリビューションであれば追加のインストールは不要である。
BSD構文のf
BSD構文ではfがツリー表示を意味する。ps auxに付けたps auxfが広く使われている。
$ ps auxf
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 21152 11520 ? Ss 12:58 0:00 /sbin/init
...
root 175 0.0 0.1 12052 7168 ? Ss 12:59 0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 383 0.0 0.1 16168 8832 ? Ss 13:01 0:00 \_ sshd: alice [priv]
alice 394 0.0 0.1 16392 6416 ? S 13:01 0:00 | \_ sshd: alice@notty
alice 395 0.0 0.0 2380 1408 ? Ss 13:01 0:00 | \_ sh -c top -b -d 60
alice 396 0.0 0.0 9020 4992 ? S 13:01 0:00 | \_ top -b -d 60
CPU使用率やメモリ使用量とツリーを同時に確認できるため、負荷の原因を親子関係とあわせて追う場合に便利である。
UNIX構文と混ぜてps -e fのようにも書ける。空白を詰めてps -efと書くとUNIX構文の-f(詳細フォーマット)になり、ツリーにはならない。
fを単独で使うと、自分の実効ユーザーIDで動いていて、かつ同じ端末に結び付いたプロセスだけが対象になる。
$ ps f
PID TTY STAT TIME COMMAND
629 pts/0 Ss+ 0:00 sh -c bash /home/alice/report.sh > /home/alice/report.log 2>&1
630 pts/0 S+ 0:00 \_ bash /home/alice/report.sh
634 pts/0 R+ 0:00 \_ ps f
自分のシェルから何が起動されているかだけを見たい場合に使う。
-Hはインデントで階層を表す
-Hもツリー表示だが、罫線を描かずインデントの深さだけで階層を表す。
$ ps -ef -H
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:58 ? 00:00:00 /sbin/init
root 24 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-journald
systemd+ 73 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-resolved
message+ 82 1 0 12:58 ? 00:00:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 87 1 0 12:58 ? 00:00:00 /usr/lib/systemd/systemd-logind
root 93 1 0 12:58 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 94 93 0 12:58 ? 00:00:00 nginx: worker process
www-data 95 93 0 12:58 ? 00:00:00 nginx: worker process
www-data 96 93 0 12:58 ? 00:00:00 nginx: worker process
www-data 97 93 0 12:58 ? 00:00:00 nginx: worker process
syslog 99 1 0 12:58 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE
root 175 1 0 12:59 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 383 175 0 13:01 ? 00:00:00 sshd: alice [priv]
alice 394 383 0 13:01 ? 00:00:00 sshd: alice@notty
alice 395 394 0 13:01 ? 00:00:00 sh -c top -b -d 60
alice 396 395 0 13:01 ? 00:00:00 top -b -d 60
階層が深くなるとインデントだけでは追いにくいため、通常は--forestのほうが読みやすい。-Hのインデントは1階層あたり2文字で一定のため、出力をスクリプトで加工する場合に扱いやすい。
表示する項目を選ぶ(-o)
-oと組み合わせると、必要な列だけを並べたツリーになる。
$ ps -eo pid,ppid,user,args --forest
PID PPID USER COMMAND
1 0 root /sbin/init
24 1 root /usr/lib/systemd/systemd-journald
73 1 systemd+ /usr/lib/systemd/systemd-resolved
82 1 message+ @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
87 1 root /usr/lib/systemd/systemd-logind
93 1 root nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
94 93 www-data \_ nginx: worker process
95 93 www-data \_ nginx: worker process
96 93 www-data \_ nginx: worker process
97 93 www-data \_ nginx: worker process
99 1 syslog /usr/sbin/rsyslogd -n -iNONE
175 1 root sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
383 175 root \_ sshd: alice [priv]
394 383 alice | \_ sshd: alice@notty
395 394 alice | \_ sh -c top -b -d 60
396 395 alice | \_ top -b -d 60
-oで列を選ぶ場合も、ツリーはコマンドを表示する列に描かれる。argsやcommのようなコマンド列を含めない場合、階層は表示されない。
$ ps -e --forest -o pid,stat
PID STAT
1 Ss
24 S<s
73 Ss
82 Ss
87 Ss
93 Ss
94 S
実務では、必要な列を並べてless -Sに渡すと読みやすい。-Sにより長い行が折り返されず、横スクロールでツリーを保ったまま読める。
$ ps -eo pid,ppid,user,pcpu,pmem,args --forest | less -S
コマンド列は最後に置く。途中に置くと列幅が制限され、ツリーのインデントの分だけコマンドが切り詰められる。
$ ps -eo args,pid --forest
COMMAND PID
/sbin/init 1
/usr/lib/systemd/systemd-jo 24
/usr/lib/systemd/systemd-re 73
@dbus-daemon --system --add 82
表示対象を絞る
--forestが描く階層は、選択の結果に残ったプロセスの間だけで組み立てられる。選択から漏れた親は、階層の途中であっても表示されない。
-uでユーザーを指定すると、そのユーザーのプロセスだけでツリーを組み立てる。-uは実効ユーザーIDによる選択で、実ユーザーIDで選ぶ場合は-Uを使う。
$ ps -f --forest -u alice
UID PID PPID C STIME TTY TIME CMD
alice 628 611 0 13:04 ? 00:00:00 sshd: alice@pts/0
alice 629 628 0 13:04 pts/0 00:00:00 \_ sh -c bash /home/alice/report.sh > /home/alice/report.log 2>&1
alice 630 629 0 13:04 pts/0 00:00:00 \_ bash /home/alice/report.sh
alice 637 630 0 13:04 pts/0 00:00:00 \_ ps -f --forest -u alice
alice 394 383 0 13:01 ? 00:00:00 sshd: alice@notty
alice 395 394 0 13:01 ? 00:00:00 \_ sh -c top -b -d 60
alice 396 395 0 13:01 ? 00:00:00 \_ top -b -d 60
alice 610 1 20 13:04 ? 00:00:00 /usr/bin/ssh -tt localhost bash /home/alice/report.sh > /home/alice/report.log 2>&1
alice 382 1 0 13:01 ? 00:00:00 /usr/bin/ssh -n localhost top -b -d 60
alice 191 1 0 12:59 ? 00:00:00 /usr/lib/systemd/systemd --user
alice 192 191 0 12:59 ? 00:00:00 \_ (sd-pam)
alice 179 1 0 12:59 ? 00:00:00 /bin/bash -c sleep 3000 & sleep 3000 & wait
alice 181 179 0 12:59 ? 00:00:00 \_ sleep 3000
alice 182 179 0 12:59 ? 00:00:00 \_ sleep 3000
rootが動かしている親プロセスは対象から外れるため、sshd: alice [priv]は現れずsshd: alice@pts/0が根になっている。
コマンド名で絞る-Cも使える。マスタープロセスとワーカープロセスの関係を確認する場合に便利である。
$ ps -f --forest -C nginx
UID PID PPID C STIME TTY TIME CMD
root 93 1 0 12:58 ? 00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 94 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 95 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 96 93 0 12:58 ? 00:00:00 \_ nginx: worker process
www-data 97 93 0 12:58 ? 00:00:00 \_ nginx: worker process
-pでPIDを1つだけ指定すると、選択の結果が1プロセスになるため階層は現れない。
$ ps -f --forest -p 396
UID PID PPID C STIME TTY TIME CMD
alice 396 395 0 13:01 ? 00:00:00 top -b -d 60
同じセッションに属するプロセスをまとめて見たい場合は、セッションIDで絞る-sを使う。セッションリーダーを根とした階層を確認できる。セッションIDはps -o sid=で調べる。
$ ps -o sid= -p 396
395
$ ps -f --forest -s 395
UID PID PPID C STIME TTY TIME CMD
alice 395 394 0 13:01 ? 00:00:00 sh -c top -b -d 60
alice 396 395 0 13:01 ? 00:00:00 \_ top -b -d 60
対象のPIDである396の実際の親はsshdだが、sshdは別のセッションに属するため表示されない。
PIDを複数指定すれば、指定した範囲での親子関係を確認できる。
$ ps --forest -o pid,args -p 395,396
PID COMMAND
395 sh -c top -b -d 60
396 \_ top -b -d 60
grepすると階層が読めなくなる
--forestの出力をgrepに通すと、罫線だけが残って親子関係が追えなくなる。
$ ps -ef --forest | grep -E 'sshd|top'
root 175 1 0 12:59 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 383 175 0 13:01 ? 00:00:00 \_ sshd: alice [priv]
alice 394 383 0 13:01 ? 00:00:00 | \_ sshd: alice@notty
alice 395 394 0 13:01 ? 00:00:00 | \_ sh -c top -b -d 60
alice 396 395 0 13:01 ? 00:00:00 | \_ top -b -d 60
root 611 175 0 13:04 ? 00:00:00 \_ sshd: alice [priv]
alice 628 611 0 13:04 ? 00:00:00 \_ sshd: alice@pts/0
alice 652 630 0 13:04 pts/0 00:00:00 \_ grep -E sshd|top
alice 382 1 0 13:01 ? 00:00:00 /usr/bin/ssh -n localhost top -b -d 60
grep自身の行は親のbashが消えたまま深い位置に残る。絞り込みが必要な場合は、-uや-Cなどps側の選択オプションを使う。特定のプロセスの周辺だけを見たい場合は、セッションIDで絞る方法が使える。
$ ps -f --forest -s $(ps -o sid= -p 396)
–sortとは併用しない
--sortを付けると出力が壊れる。多くのプロセスが欠落し、残った行の階層も正しく描かれない。
$ ps -ef --forest --sort=-pcpu
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 12:58 ? 00:00:00 /sbin/init
alice 815 1 18 13:14 ? 00:00:00 /usr/bin/ssh -tt localhost bash /home/alice/report.sh > /home/alice/report.log 2>&1
同じスクリプトの中で--sortを外して数えると30行あるが、--sort=-pcpuを付けると見出しを含めて3行しか残らない。どれだけ欠落するかは環境や実行のたびに変わる。ツリーの組み立てと並べ替えは両立しないため、並べ替えたい場合は--forestを外す。
スレッド表示とは併用できない
スレッドを表示する-Lとツリー表示は同時に指定できず、エラーになる。--forestだけでなくfと-Hも同じである。
$ ps -efL --forest
error: thread display conflicts with forest display
プロセスの階層とスレッドをまとめて見たい場合はpstree -pを使う。スレッドは{rsyslogd}(105)のように波括弧で表示される。
pstreeとの使い分け
| コマンド | 向いている用途 |
|---|---|
ps --forest | PIDやCPU使用率などの列とツリーを同時に確認する |
pstree | 構造だけを素早く把握する、同じ枝をまとめて見る |
pstreeは同じ形の枝を4*[nginx]のようにまとめるため全体像をつかみやすい。ps --forestは1プロセス1行で、-oにより見たい情報を並べられる。詳しくは【Linux】pstreeコマンドでプロセスの親子関係をツリー表示する
を参照。
macOSでは使えない
macOSのpsはBSD由来のため、ツリー表示の--forestとBSD構文のfのどちらも持たない。
$ ps --forest
ps: illegal option -- -
usage: ps [-AaCcEefhjlMmrSTvwXx] [-O fmt | -o fmt] [-G gid[,gid...]]
[-g grp[,grp...]] [-u [uid,uid...]]
$ ps auxf
ps: illegal option -- f
詳細フォーマットの-fは存在するため、ps -efは動作する。ツリー表示だけが使えない。
macOSでツリー表示したい場合はbrew install pstreeでpstreeを導入する。Homebrewで入るpstreeはLinuxのpsmisc版とは別実装で、オプションの体系も異なる。
