プロセス管理の初歩テクニック
Index
- 一言
- Terminalログアウト後もプロセスを残す
- プロセスの2重起動防止
- 簡単に不要なプロセスをkillする
- tmuxの薦め
一言
はてなって不思議なコミュニティーで具体的な実装や調査分析よりも便利なコマンドとかを紹介するネタが何故か重宝されるようなので、良く使うプロセス管理系コマンドの初歩テクニックを書いてみます。( コマンドの学習をより必要とする人が多く一般的な話だからでしょうか? )
Terminalログアウト後もプロセスを残す
単一の処理で長時間かかってしまうようなプログラムを実行後にログアウトするとプロセスが消えて悲惨な目に遭います。tmuxやscreenを使って再起動可能な設定をしている人は特に気にする必要はありませんが、これらを使っていない場合はnohupでログアウト後もプロセスを残しましょう。
$ vi nohuptest.sh #!/bin/sh sleep 1000 $ chmod +x ./nohuptest.sh $ nohup ./nohuptest.sh & [1] 13564 #nohup: ignoring input and appending output to `nohup.out' $ exit # 再度ログイン $ ps auxww | grep nohuptest yuta 13564 0.0 0.1 106088 1172 ? SN 03:56 0:00 /bin/sh ./nohuptest.sh yuta 14059 0.0 0.0 107456 948 pts/6 S+ 04:00 0:00 grep nohuptestnohupの指定を忘れてしまった場合でも途中からプロセスを残したい場合はdisownコマンドを利用すれば問題無しです。
$ ./nohuptest.sh & [1] 16004 $ disown %1 $ exit # 再度ログイン $ ps auxww | grep nohuptest yuta 16079 0.0 0.1 106088 1168 ? SN 04:17 0:00 /bin/sh ./nohuptest.sh yuta 16173 0.0 0.0 107456 948 pts/8 S+ 04:18 0:00 grep nohuptest
プロセスの2重起動防止
バッチ処理等でプロセスが2重で起動するとデータの不整合が発生する可能性があります。それを防止するためにプロセスの2重起動を防止することを考えます。プロセスの2重起動防止はプロセス名で判断するかLockファイルで実行中フラグを管理する2種類の方法が良く使われます。Lockファイルだとプロセスが途中で落ちた時に削除されない事がありずっと実行中と判断されてしまうので、プロセス名で判断する方がより良いように思います。一応二つともやり方を書いておきます。プロセスが存在するかどうかはpgrep、Lockファイル削除trapコマンドでシグナルを受け取って行います。下のスクリプトでは10秒以内に再度処理を実行しようとすると"Process is Running"と表示されると思います。
#!/bin/sh if [ $$ != `pgrep -fo $0` ]; then echo "Process is Running"; exit 1; fi echo "Process is Started" sleep 10; echo "Process is Done";#!/bin/sh lockfile="$0.lock" trap 'echo "trapped."; rm -f ${lockfile}; exit 1' 1 2 3 15 if [ -e $lockfile ];then echo "Process is Running" fi touch $lockfile; echo "Process is Started" sleep 10 rm $lockfile echo "Process is Done"trapはシグナルを受け取るコマンドです。一般的には1 2 3 15のkillシグナルを受けるように設定するようです。番号の意味ですが1は再起動、2はCTR + Cの割り込み、3はCTR + \の中断、15はプロセスの終了を表します。trapコマンドで気をつけたいのが9の強制終了を受け取る事が出来ません(9を指定しても)。よってkill -9で指定されるとtrap出来ずlockファイルが残ってしまうので注意が必要です。上のshellscriptをtraptest.shとし、killの操作を実行してみます。
$ ./traptest.sh #別のterminal windowからpgrepで検知してkill $ pgrep -f "traptest" | xargs kill # trapされている事が分かる。 Process is Started trapped.$ ./traptest.sh #別のterminal windowからpgrepで検知してkill -9 $ pgrep -f "traptest" | xargs kill -9 # trapされていない事が分かる。 Process is Started zsh: killed ./traptest.sh # traptest.sh.lockが残ってしまう。 $ ls -al -rwxr-xr-x. 1 yuta yuta 237 8月 19 02:06 2013 traptest.sh -rw-r--r--. 1 yuta yuta 0 8月 19 02:07 2013 traptest.sh.lock
簡単に不要なプロセスをkillする
psという起動中のプロセスを表示する代表的なコマンドがありますが、killしたい場合は少々使いづらかったりします。psには自身のコマンドがどうしても含まれてしまうのでそれをgrep -vで除外する必要があります。例えばhttpdプロセスを全部削除したい場合は以下のようにpsとkillをパイプします。
$ ps auxww | grep httpd ps auxww | grep httpd root 2149 0.0 0.8 264888 8468 ? Ss Aug18 0:03 /usr/sbin/httpd apache 2158 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2160 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2161 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2162 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2163 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2165 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2166 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd apache 2167 0.0 0.5 264888 5280 ? S Aug18 0:00 /usr/sbin/httpd yuta 4741 0.0 0.0 107460 948 pts/0 S+ 02:14 0:00 grep httpd $ ps auxww | grep httpd | grep -v grep | awk '{print $2}' | xargs sudo kill $ ps auxww | grep httpd yuta 4810 0.0 0.0 107456 940 pts/0 S+ 02:17 0:00 grep httpdgrep -vとawkがかなり冗長的な命令のように思えてしまいます。そのように感じた人は上でも使ったpgrepでプロセス名から直接killしても良いと思います。
$ ps auxww | grep httpd root 4845 0.9 0.9 264888 9276 ? Ss 02:20 0:00 /usr/sbin/httpd apache 4848 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4849 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4850 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4851 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4852 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4853 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4854 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd apache 4855 0.0 0.5 264888 5292 ? S 02:20 0:00 /usr/sbin/httpd yuta 4859 0.0 0.0 107460 944 pts/0 S+ 02:20 0:00 grep httpd $ pgrep -f "httpd" 4845 4848 4849 4850 4851 4852 4853 4854 4855 # 4859の自身のgrepは表示されない $ pgrep -f "httpd" | xargs sudo kill $ ps auxww | grep httpd yuta 4880 0.0 0.0 107456 944 pts/0 S+ 02:23 0:00 grep httpdさらにxargsさえも使う事が面倒だという男気溢れる人は次のようにpkillもしくはkillallで一発でお別れを告げても良いと思います。
$ ps auxww | grep httpd root 4902 0.1 0.9 264888 9272 ? Ss 02:25 0:00 /usr/sbin/httpd apache 4905 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4906 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4907 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4908 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4909 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4910 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4911 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd apache 4912 0.0 0.5 264888 5288 ? S 02:25 0:00 /usr/sbin/httpd yuta 4922 0.0 0.0 107460 948 pts/0 S+ 02:26 0:00 grep httpd $ sudo pkill -f "httpd" $ ps auxww | grep httpd yuta 4929 0.0 0.0 107456 940 pts/0 S+ 02:27 0:00 grep httpd $ sudo /etc/init.d/httpd restart $ ps auxww | grep httpd root 5045 0.1 0.9 264888 9236 ? Ss 02:37 0:00 /usr/sbin/httpd apache 5048 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5049 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5050 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5051 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5052 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5053 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5054 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd apache 5055 0.0 0.5 264888 5296 ? S 02:37 0:00 /usr/sbin/httpd yuta 5062 0.0 0.0 107460 944 pts/0 S+ 02:38 0:00 grep httpd $ sudo killall "httpd" $ ps auxww | grep httpd yuta 5067 0.0 0.0 107456 944 pts/0 S+ 02:38 0:00 grep httpd
tmuxの薦め
あまりプロセスと関係ありませんが、screenを使っている人は更に機能豊富なtmuxを乗り換えると良いと思います。1つのプロセスでworking spaceとなるwindowを複数立てたりpaneと呼ばれる単位の子windowへの分割もできます。またtmuxユーザーはちゃんとデタッチすれば、上で紹介したnohupやdisownを意識する必要が無いです。tmuxはyumで簡単にinstallも出来ますし、keybindもscreenとさほど変わらないように設定できます。設定ファイルは以下が参考になると思います。zsh, tmux, vimで構築する快適なCUI環境 2/3 「tmux」編 - ナレッジエース .tmux.confを設定し、tmuxコマンドで起動します。これほど便利なtmuxをまだ使わずにscreenにしがみつく開発者が同環境に存在した場合、今回覚えたpgrepやkillallでscreenプロセスを一匹残らず駆逐するのも良いかと思います。(冗談です)
$ sudo yum install tmux -y $ vi ~/.tmux.conf #新しいウィンドウのベース番号 set-option -g base-index 1 #全てのベルを無視 set-option -g bell-action none #各セッションで保持するバッファ数 set-option -g buffer-limit 20 #256色端末を使用 set-option -g default-terminal "xterm" set-option -g default-command /usr/local/bin/zsh set-option -g default-shell /usr/local/bin/zsh #ウィンドウ履歴で保持される最大行数 set-option -g history-limit 5000 #Escapeキー入力時の待ち時間(0.5秒)をキャンセル set-option -s escape-time 0 #ウィンドウを実行コマンド名で自動リネーム set-window-option -g automatic-rename on #スクロールモード、コピーモード、選択モードで vi のキーバインドを使う set-window-option -g mode-keys vi #ウィンドウで動作があるとステータスラインでハイライト set-window-option -g monitor-activity on #UTF-8 シーケンスが現れることに備える set-window-option -g utf8 on #set-option -g mouse-resize-pane on #set-option -g mouse-select-pane on # prefix + r で設定ファイルを再読み込み set-option -g prefix C-g unbind r bind r source-file ~/.tmux.conf # キーバインド # 各種ペインの移動 bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R # 各種ペインのリサイズ bind H resize-pane -L 5 bind J resize-pane -D 5 bind K resize-pane -U 5 bind L resize-pane -R 5 #マウススクロールバック set-window-option -g mode-mouse on #status line set -g status-interval 5 set -g status-fg cyan set -g status-bg black set -g status-left-length 40 set -g status-left '#[fg=white,bg=blue]#H#[fg=white,bg=black]:#[fg=white,bg=black][#S#[fg=white,bg=black]][#[fg=white,bg=black]' set -g status-right '#[fg=white,bg=cyan][CPU=#(cpu.sh) MEM=#(mem.sh)]#[fg=black,bg=green][%Y/%m/%d(%a)%H:%M]#[default]' setw -g window-status-current-fg cyan setw -g window-status-current-bg black setw -g window-status-current-attr bold#,underscore # 以上が設定ファイル $ cat mem.sh cpu.sh #!/bin/sh free | grep "^Mem:" | awk '{printf ("%3d%\n", (($3 / $2) * 100) + 0.5)}' #!/bin/sh top -bn1 | grep "^Cpu(s)" | sed "s/.*, *\([0-9.]*\)%id.*/\1/" | awk '{printf ("%3d%\n", 100 - $1 + 0.5)}' # tmuxの起動 $ tmux # screenを使っている奴らを駆逐する。 $ sudo killall "screen"