[Linux] プロセスIDを調べてみる | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

Linux上では、実行処理されているプログラムがプロセスという形で扱われ、それを見ることで正常に処理が進んでいるかを確認することができます。
Linuxでプロセスを調べる代表的なコマンドとしてpsコマンドがありますが、そのほかの方法でもプロセスを知ることができます。


サーバー管理者からみると、プロセスは名前で判別したほうがもちろんわかりやすいのですが、システム上から見た場合、同名のプロセスもあったりするためかえって判別がつきにくくなります。
プロセスは個別に受け持つ役割があるため、別のプロセスを間違って操作してしまうと、親子関係にあるプロセスなどへ影響が及んでしまいます。
そのため、プロセスにはユニークなプロセスIDが割り振られています。


プロセスをプログラムから操作する場合は、このプロセスIDを用いて操作するのが一般的です。
そのプロセスIDを取得する方法をいくつか紹介します。



もっともポピュラーなpsコマンド


プロセスの状態を調べるための最もよく知られているのはpsコマンドだと思います。


# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   2064   632 ?        Ss   Feb09   0:02 init [3]
root         2  0.0  0.0      0     0 ?        S    Feb09   0:00 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Feb09   0:00 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Feb09   0:00 [watchdog/0]
root         5  0.0  0.0      0     0 ?        S    Feb09   0:00 [migration/1]
root         6  0.0  0.0      0     0 ?        SN   Feb09   0:00 [ksoftirqd/1]
root         7  0.0  0.0      0     0 ?        S    Feb09   0:00 [watchdog/1]

そのサーバー上で動いている全てのプロセスが一覧表示され、状態やどれくらいの負荷がある(CPUやメモリ利用率)かを表示してくれます。
オプションも多彩にありますので、見たい情報に併せて変えてみたり、特定のプロセスに絞ってみたい場合は、grepと組み合わせてみると良いでしょう。


# ps -ef | grep httpd
root      6910  6822  0 16:24 pts/1    00:00:00 grep httpd
apache   10270 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10271 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10272 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10273 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10274 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10277 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10279 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
apache   10281 17700  0 Feb15 ?        00:00:00 /usr/sbin/httpd
root     17700     1  0 Feb10 ?        00:00:00 /usr/sbin/httpd

左から2番目がプロセスIDとなり、3番目が親のプロセスIDとなります。
上記の場合は、17700がApacheの親プロセスとなり、それに8つの子プロセスが起動しているのがわかります。



psコマンドをグラフィカルにしたpstreeコマンド


psコマンドはフラットにプロセスを表示するため、多少見づらいところがあります。
pstreeコマンドは、プロセスをツリー上に見やすく表示してくれます。


# pstree -cpn
init(1)┬ migration/0(2)
       ├ ksoftirqd/0(3)
       ├ watchdog/0(4)
       ├ migration/1(5)
(略)
        └ httpd(17700) ┬ httpd(10270)
                      ├ httpd(10271)
                      ├ httpd(10272)
                      ├ httpd(10273)
                      ├ httpd(10274)
                      ├ httpd(10277)
                      ├ httpd(10279)
                      └ httpd(10281)

上記のように、httpdプロセスの親プロセスと子プロセスの関係がわかりやすく表示されます。
また、「-p」オプションを付けることでプロセスIDを表示することもできます。



特定のコマンド名からプロセスIDを表示するpidofコマンド


こちらは純粋にプロセスIDだけを表示してくれるコマンドです。


# pidof /usr/sbin/httpd
17700 10281 10279 10277 10274 10273 10272 10271 10270

上記のようにhttpdコマンドを実行しているプロセスIDを全て表示します。
単なるIDの羅列なため、サーバーを管理する上ではあまり使い道がないのですが、プロセスを操作するプログラムを書いたりする場合は、余計な情報が含まれないため有効だったりします。


パッケージで導入した場合に付属する自動起動スクリプト(/etc/rc.d/init.d/)では、停止時にpidofコマンドを使ってプロセスIDを取得し、TERMシグナルをkillコマンドで送って停止させています。(※1)

例えば、Apacheの自動起動スクリプトを覗いてみると


stop() {
    echo -n $"Stopping $prog: "
    killproc -d 10 $httpd
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}

停止命令(stopオプション)をつけた場合に呼び出される関数ですが、その中でkillprocという関数がさらに呼び出されています。
killproc関数は、このApacheの自動起動スクリプトで読み込まれているfunctionsというファイルの中で定義されています。
さらにkillprocというコマンドを覗いてみると、その中で__pids_pidofという関数が呼び出されており(※1)、その中身は


# Output PIDs of matching processes, found using pidof
__pids_pidof() {
    pidof -c -o $$ -o $PPID -o %PPID -x "$1" || \
        pidof -c -o $$ -o $PPID -o %PPID -x "${1##*/}"
}

のようにpidofコマンドが呼び出されてプロセスIDを取得しています。


※1 実際にはPIDファイルを優先的に探し、存在する場合はその中に書かれているプロセスIDを利用します。
※2 Linuxのディストリビューションやパッケージのバージョンによって内容が異なってきます。



条件付きでプロセスIDだけを取り出せるpgrepコマンド


出力結果は、pidofコマンドに似ているのですが、取り出す際に条件もつけられるpgrepコマンドというのもあります。

実行方法は、pidofと同様にコマンド名を指定します。


# pgrep -f /usr/sbin/httpd
10270
10271
10272
10273
10274
10277
10279
10281
17700

で、さらにこのApacheのプロセスの中からrootで実行しているプロセス(親プロセス)を取り出してみます。


# pgrep -f /usr/sbin/httpd -u root
17700

逆に、root以外(Apacheのユーザーであるapacheユーザー)で実行されているプロセスを指定してみると


# pgrep -f /usr/sbin/httpd -u apache
10270
10271
10272
10273
10274
10277
10279
10281

親プロセス以外のプロセスIDが表示されましたね。
場合によっては、pidofコマンドよりこちらの方がプロセスIDを取得しやすいかもしれません。



プロセスIDを記したPIDファイル


起動するコマンドの種類によっては、プロセス起動時にプロセスIDをファイルに保存する動きをするものがあります。


# ls /var/run/
NetworkManager  auditd.pid  console  dbus  klogd.pid  netreport  pcscd.pid
(略)

中を見てみると、単純に親プロセスのIDだけが記載されています。


# cat /var/run/httpd.pid
17700 

先ほどのApacheの停止スクリプトでも、最初にこのプロセスIDファイルが存在するかをチェックし、存在する場合はその中に記載されているプロセスIDを停止させるような動きをしています。



/proc プロセス情報を含んだ特殊なファイルシステム


/procディレクトリ以下にもプロセスに関する情報が保存されています。


# ls /proc/
1  10277  165  1982  2043  2235  2454  2598  2668  367  6788  9  cmdline  fb
(略) 

番号が書かれたディレクトリがずらずらと表示されます。
この番号はプロセスIDを示していて、これらの中にはそのプロセスIDが処理するのに必要な、さまざまな情報が格納されています。


# ls -o /proc/17700
合計 0
dr-xr-xr-x 2 root 0  2月 17 11:21 attr
-r-------- 1 root 0  2月 18 16:32 auxv
-r--r--r-- 1 root 0  2月 16 10:24 cmdline
-r--r--r-- 1 root 0  2月 18 16:32 cpuset
lrwxrwxrwx 1 root 0  2月 18 16:32 cwd -> /
-r-------- 1 root 0  2月 18 16:32 environ
lrwxrwxrwx 1 root 0  2月 10 11:24 exe -> /usr/sbin/httpd
dr-x------ 2 root 0  2月 17 11:21 fd
-rw-r--r-- 1 root 0  2月 18 16:32 loginuid
-r--r--r-- 1 root 0  2月 18 16:32 maps
-rw------- 1 root 0  2月 18 16:32 mem
-r--r--r-- 1 root 0  2月 18 16:32 mounts
-r-------- 1 root 0  2月 18 16:32 mountstats
-rw-r--r-- 1 root 0  2月 18 16:32 oom_adj
-r--r--r-- 1 root 0  2月 18 16:32 oom_score
lrwxrwxrwx 1 root 0  2月 18 16:32 root -> /
-r--r--r-- 1 root 0  2月 18 16:32 schedstat
-r-------- 1 root 0  2月 18 16:32 smaps
-r--r--r-- 1 root 0  2月 16 10:34 stat
-r--r--r-- 1 root 0  2月 18 16:32 statm
-r--r--r-- 1 root 0  2月 16 10:24 status
dr-xr-xr-x 3 root 0  2月 17 11:21 task
-r--r--r-- 1 root 0  2月 18 16:32 wchan

先ほどのPIDファイルは消すことはできますが、こちらは特殊なファイルとなっており消すことはできません。
ですので、確実に起動しているプロセスIDの一覧となります。
PIDファイルは一種のロックファイル(プロセスを2重起動しないように)のような扱いなので、/procディレクトリ以下にそのプロセスIDがあるかを厳密にチェックしたほうが、プロセスの稼動を確実に確認することができます。


- 更新情報

2009.02.18 pgrepコマンドに関する情報を追加しました。