我正在编写一个脚本,用于检测我的 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
确保即使脚本崩溃时也会删除文件。详细信息将取决于您到底想要做什么,以及为什么需要检测正在运行的实例。