O script Bash para contar o número de instâncias de execuções não funciona

O script Bash para contar o número de instâncias de execuções não funciona

Estou escrevendo um script que detecta se já existe alguma instância dele em execução na minha máquina Linux e mostra na tela o número de instâncias.

O conteúdo do script "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

Ao executar o script ele mostra por tela:

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

Mas eu esperava que isso mostrasse:

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

Não entendo porque se eu executar ps -ef | grep detect_itself.sh | grep -v -i grep | wc -lele retorna o valor 1, mas se eu salvar esse valor em uma variável e mostrar com echo ele mostra 2.

Responder1

Isso está acontecendo porque você está executando o pscomando em um subshell. Quando você executa isso:

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

Na verdade, isso bifurca um novo subshell para executar esse comando. Como esse fork é uma cópia do pai, agora há duas detect_itself.shinstâncias em execução. Para ilustrar, execute isto:

#!/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`"

Isso deve imprimir:

$ 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

Felizmente, existe um aplicativo para isso! Esse tipo de coisa é exatamente o motivo pgrepde existir. Então mude seu script para:

#!/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`

Isso deve imprimir:

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

IMPORTANTE: isso não é uma coisa segura de se fazer. Por exemplo, se você tiver um script chamado this_will_detect_itself, isso será contado. se você tiver o arquivo aberto em um editor de texto, isso também será contabilizado. Uma abordagem muito mais robusta para esse tipo de coisa é usar um arquivo de bloqueio. Algo como:

#!/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

Ou, melhor ainda, use trappara garantir que o arquivo seja removido mesmo quando o script travar. Os detalhes dependerão exatamente do que você deseja fazer e do motivo pelo qual você precisa detectar a instância em execução.

informação relacionada