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からshshから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で列を選ぶ場合も、ツリーはコマンドを表示する列に描かれる。argscommのようなコマンド列を含めない場合、階層は表示されない。

$ 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 --forestPIDや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 pstreepstreeを導入する。Homebrewで入るpstreeはLinuxのpsmisc版とは別実装で、オプションの体系も異なる。

参考