Скрипт 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`

Это фактически разветвляет новую подоболочку для запуска этой команды. Поскольку эта разветвленная оболочка является копией родительской, теперь запущено два 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, чтобы убедиться, что файл удаляется даже при сбое скрипта. Детали будут зависеть от того, что именно вы хотите сделать, от того, почему вам нужно обнаружить запущенный экземпляр.

Связанный контент