Bash-Skript zum Zählen der Anzahl von Ausführungsinstanzen funktioniert nicht

Bash-Skript zum Zählen der Anzahl von Ausführungsinstanzen funktioniert nicht

Ich schreibe ein Skript, das erkennt, ob auf meinem Linux-Rechner bereits eine Instanz davon ausgeführt wird, und die Anzahl der Instanzen auf dem Bildschirm anzeigt.

Der Inhalt des Skripts „detect_itself.sh“ ist:

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

Beim Ausführen des Skripts wird auf dem Bildschirm Folgendes angezeigt:

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

Aber ich habe erwartet, dass Folgendes angezeigt wird:

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

Ich verstehe nicht, warum beim Ausführen ps -ef | grep detect_itself.sh | grep -v -i grep | wc -lder Wert 1 zurückgegeben wird, wenn ich diesen Wert aber in einer Variablen speichere und mit Echo anzeige, jedoch 2 angezeigt wird.

Antwort1

Dies liegt daran, dass Sie den Befehl in einer Subshell ausführen ps. Wenn Sie Folgendes ausführen:

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

Dadurch wird tatsächlich eine neue Subshell erstellt, in der dieser Befehl ausgeführt wird. Da diese Abzweigung eine Kopie der übergeordneten Shell ist, werden jetzt zwei detect_itself.shInstanzen ausgeführt. Führen Sie zur Veranschaulichung Folgendes aus:

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

Das sollte ausgegeben werden:

$ 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

Glücklicherweise gibt es dafür eine App! Genau diese Art von Dingen pgrepexistiert. Ändern Sie also Ihr Skript wie folgt:

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

Das sollte ausgegeben werden:

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

WICHTIG: das ist nicht sicher. Wenn Sie beispielsweise ein Skript mit dem Namen haben this_will_detect_itself, wird das gezählt. Wenn Sie die Datei in einem Texteditor geöffnet haben, wird das auch gezählt. Ein weitaus robusterer Ansatz für solche Dinge ist die Verwendung einer Sperrdatei. So etwas wie:

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

Oder, noch besser, prüfen Sie trap, ob Sie sicherstellen können, dass die Datei auch dann entfernt wird, wenn das Skript abstürzt. Die Details hängen davon ab, was genau Sie tun möchten und warum Sie die laufende Instanz erkennen müssen.

verwandte Informationen