実行インスタンスの数をカウントする Bash スクリプトが機能しない

実行インスタンスの数をカウントする Bash スクリプトが機能しない

Linux マシン上ですでに実行されているインスタンスがあるかどうかを検出し、インスタンスの数を画面に表示するスクリプトを作成しています。

「detect_itself.sh」スクリプトの内容は次のとおりです。

#!/bin/sh

INSTANCES_NUMBER=`ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l`
echo "Number of detect_itself.sh instances running now =" $INSTANCES_NUMBER
echo "Second method:"
ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l
echo "Third method:"
echo `ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l`
echo "Please, press a key"
read -r key

スクリプトを実行すると、画面に次のように表示されます。

Number of detect_itself.sh instances running now = 2
Second method:
1
Third method:
2
Please, press a key

しかし、私は次のように表示されると予想しました:

Number of detect_itself.sh instances running now = 1
Second method:
1
Third method:
1
Please, press a key

ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l実行すると値 1 が返されるのに、この値を変数に保存して echo で表示すると 2 が表示されるのはなぜかわかりません。

答え1

psこれは、サブシェルでコマンドを実行しているために発生します。これを実行すると、

INSTANCES_NUMBER=`ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l`

実際には、そのコマンドを実行するための新しいサブシェルがフォークされます。このフォークは親のコピーであるため、現在 2 つのdetect_itself.shインスタンスが実行されています。説明のために、以下を実行します。

#!/bin/sh
echo "Running the ps command directly:"
ps -ef | grep detect_itself.sh | grep -v -i grep
echo "Running the ps command in a subshell:"
echo "`ps -ef | grep detect_itself.sh | grep -v -i grep`"

次のように印刷されます:

$ test.sh
Running the ps command directly:
terdon   25683 24478  0 14:58 pts/11   00:00:00 /bin/sh /home/terdon/scripts/detect_itself.sh
Running the ps command in a subshell:
terdon   25683 24478  0 14:58 pts/11   00:00:00 /bin/sh /home/terdon/scripts/detect_itself.sh
terdon   25688 25683  0 14:58 pts/11   00:00:00 /bin/sh /home/terdon/scripts/detect_itself.sh

幸いなことに、そのためのアプリがあります。このようなアプリがpgrep存在するのは、まさにそのためです。スクリプトを次のように変更します。

#!/bin/sh
instances=`pgrep -fc detect_itself.sh`
echo "Number of detect_itself.sh instances running now = $instances"
echo "Second method:"
ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l
echo "Third method (wrong):"
echo `ps -ef | grep detect_itself.sh | grep -v -i grep | wc -l`

次のように印刷されます:

$ detect_itself.sh
Number of detect_itself.sh instances running now = 1
Second method:
1
Third method (wrong):
2

重要: これは安全な方法ではありません。たとえば、 というスクリプトがある場合this_will_detect_itself、それはカウントされます。ファイルをテキスト エディターで開いている場合も、それはカウントされます。このような場合のより堅牢な方法は、ロック ファイルを使用することです。次のようになります。

#!/bin/sh

if [[ -e /tmp/I_am_running ]]; then
    echo "Already running! Will exit."
    exit
else
    touch /tmp/I_am_running
fi
## do whatever you want to do here

## remove the lock file at the end
rm /tmp/I_am_running

または、trapスクリプトがクラッシュした場合でもファイルが削除されるようにするには、 の使用を検討してください。詳細は、具体的に何をしたいのか、実行中のインスタンスを検出する必要がある理由によって異なります。

関連情報