用于计算执行实例数量的 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子 shell 中运行该命令。当你运行这个时:

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

这实际上分叉了一个新的子 shell 来运行该命令。因为这个分叉是父级的副本,所以现在有两个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确保即使脚本崩溃时也会删除文件。详细信息将取决于您到底想要做什么,以及为什么需要检测正在运行的实例。

相关内容