.................................................
<< 12年01月 >>
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31


最近のコメント
10/07 北本
09/29 拝承
07/28 北本
07/20 ばてれん
10/26 北本
.............................
何となくリンク
.............................

2020年
02月
05月
09月
2019年
04月 05月
08月 09月
2018年
01月 02月 03月
04月 05月 06月
09月
10月
2017年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2016年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2015年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2014年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2013年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2012年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2011年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2010年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2009年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2008年
01月 02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月
2007年
02月 03月
04月 05月 06月
07月 08月 09月
10月 11月 12月

レスを書き込みます




Linux におけるバッククォートPIDについて 2012年1月13日(金)23時10分
分類:マメ知識 [この記事のURL]

Linux上で、シェルを作成する際、自分自身が起動しているかどうか。
つまり二重起動チェックの実装について面白いことが判明した。

test.sh というシェルを作ります。
このシェルが既に起動されていれば、何もせず終了させる。
といったことをやりたい。

test.sh の中身
-------------------------------
#!/bin/sh
ps -ef | grep $0 | grep -v grep
-------------------------------

これを実行すると、普通に考えると
-----------------------------------------------------------------
root 7838 7599 0 22:52 pts/0 00:00:00 /bin/sh ./test.sh
-----------------------------------------------------------------

のように1行のみ出力される筈である。実際大体は1行で出力される。
これは自分自身が実行されているのだから当たり前だ。
なので、出力された行数を取得し、1以外だったら終了とすればいい。

なんだ、簡単じゃねぇーか。と思いきやそこに罠が潜んでます。
何度かやると気付きますが、たまーに以下のように出力されます。
-----------------------------------------------------------------
root 7834 7599 0 22:52 pts/0 00:00:00 /bin/sh ./test.sh
root 7837 7834 0 22:52 pts/0 00:00:00 /bin/sh ./test.sh
-----------------------------------------------------------------

2行出力っ?! なんで?!
答えはLinuxにはサブシェルとかいう概念があるから。
起動されたtest.shのPIDは7834で、このシェルから呼び出されたコマンドは
サブシェルとして起動します。
なので下のプロセスの親PIDは7834となってます。

ここで、思いついたのは、大元のシェルのPIDを全て除外すれば、
必ず 0 になるんじゃないか? ということです。
以下のように修正しました。
--------------------------------------
ps -ef | grep "sh $0" | grep -v " $$ "
--------------------------------------

こうすることで、大元のシェルを親PIDとして持つ子プロセスは全て除外され
結果的に 0 になるという訳です。実際 0 になりました。

これで漸く解決。 と思いきや、とんでもない超展開が待っていました。
カウントを取る為、シェル内では以下のように組み込む筈です。

CNT=`ps -ef | grep "sh $0" | grep -v " $$ " | wc -l`
CNTが0以外であれば、既に同じシェルが起動中、つまり二重起動と判断できる。
ところが、何故か0〜2の何れかの値でカウントされます。
な、なんでだ!?

すると驚くべきことが判明しました。
バッククォートでコマンドを実行すると、起動シェルの子プロセスとしてではなく完全に別プロセスとして起動されるようです。

つまり、起動シェルのPIDを、親PIDとして持たないPIDが起動される!
今回実装した起動数チェックは、あくまで起動シェルのPIDを持つプロセスを全て除外するというロジックなので、起動シェルのPIDを一切持たない同じ名前のプロセスはカウントされてしまう!

これじゃ二重起動のチェックできねぇよ!
ということで、ロックファイル形式に変えるのでした(´д`)


nik5.144