• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Wiederaufruf von Script verhindern

OsunSeyi

Hacker
Hi,

Ich suche eine Möglichkeit zu verhindern, daß ein Script 2x aufgerufen wird.
Es soll, einmal gestartet, bei einem Wiederaufruf ausgeben: 'Script läuft bereits, cancel'

Einfacher Weg:
Das Script legt beim Erstaufruf eine Datei (oder einen Eintrag in einer solchen) an, und schaut jedesmal nach, ob diese bereits exisiert oder nicht.
Beim Stoppen löscht es diesen wieder... und der Weg zu einem Neuaufruf ist frei.
Nachteil: Wird das Script mal nicht sauber beendet, bleibt die Datei bestehen und muss händisch entfernt werden.

Besser:
Mit 'ps aux | grep script' wird kontrolliert, ob ein Prozess mit unserem Scriptnamen schon läuft.
Wenn ja, wird abgebrochen.

Das ist aber garnicht so einfach, weil ein Prozess mehrere Einträge erzeugen kann und diese auch nicht unbedingt gleich wieder verschwinden.
Mal abgesehen davon, daß unser zweiter Aufrufsversuch natürlich auch Einträge erzeugt.
Wie dem auch sei, ich habe schon verschiedene Versuche hinter mir, aber nichts funktioniert wirklich 100%.

zB folgender:

Code:
#!/bin/sh
# STOP
#	Stopscript zum einbinden, verhindert Wiederaufruf.
#
# Der Dateiname des aufrufenden Script "$0":

	NAME=`echo $0 | sed 's|^.*/||g'`

	 PID=`										\
#		alle Prozesse:
											\
			ps aux								|\
											\
#		auf den Namen:
											\
			egrep "$0"							|\
											\
#		im Vordergrund:
											\
			grep '+'							|\
											\
#		nur die pid:
											\
			awk '{print $2}'						|\
											\
#		ohne den aufrufenden Prozess:
											\
			sed "s|$$||g"`

# jetzt sollten genau eine Pid für jeden laufenden Prozess in "$PID" sein.
# frag am besten nicht weiter... ;-)
#
# Auf jeden Fall ist die Zahl der laufenden Prozesse unter dem Namen nicht klar.
# Darum:

	n=0

	for i in $PID ; do n=$(( $n+1 )) ; done

	if [ $n -gt 1 ] ; then

		echo $0' läuft bereits, exit'

		exit 0
	fi

# Es ist nicht der erste Versuch, dieses Script zuverlässig zu machen...
# vielleicht klappt es ja diesmal.

Tja, tut es eben nicht...
Gibt's nicht einen besseren Weg??
 

framp

Moderator
Teammitglied
OsunSeyi schrieb:
Hi,

Ich suche eine Möglichkeit zu verhindern, daß ein Script 2x aufgerufen wird.
Es soll, einmal gestartet, bei einem Wiederaufruf ausgeben: 'Script läuft bereits, cancel'

Einfacher Weg:
Das Script legt beim Erstaufruf eine Datei (oder einen Eintrag in einer solchen) an, und schaut jedesmal nach, ob diese bereits exisiert oder nicht.
Beim Stoppen löscht es diesen wieder... und der Weg zu einem Neuaufruf ist frei.
Nachteil: Wird das Script mal nicht sauber beendet, bleibt die Datei bestehen und muss händisch entfernt werden. ...
Kennst Du dieses bash Feature?
Code:
function cleanupFiles {
        rm -f lockFile 2>/dev/null
        exit
}

trap 'cleanupFiles' SIGHUP SIGINT SIGPIPE SIGTERM
Damit wird immer die Datei wieder gelöscht - egal wie das Programm beendet wird.
 
A

Anonymous

Gast
Die zweite Variante ist schwierig bei Scripten,

besser ist die einfache Variante die du angesprochen hast. Diese Datei zum Beispiel wenn es ein Systemscript ist /var/run/script.pid nennen. Bei User-Scripten dann entsprechend wo es hingehört.
Der Inhalt dieser Datei eenthält dann die PID des Prozesses, also am Anfang des Scriptes zB:
Code:
RUN_LOCK="/var/run/script.pid"
if [ ! -f "$RUN_LOCK" ]
  then 
      echo $$ > "$RUN_LOCK"
  else
#      Hier muss jetzt ausgewertet werden ob diese Prozess-ID existiert. sU.
       echo "Datei schon da"
       exit 
fi

im Elsezweig testest du dann ob es einen Prozess mit dieser PID gibt, der im Kommandoaufruf deinen Scriptnamen enthält, wenn ja, dann ist es ok und das Script wird an dieser Stelle beendet, wenn nicht dann sollte die Lockdatei nicht mehr aktuell sein und du kannst sie überschreiben (eine Warung aber dennoch dabei rausschreiben lassen, zumindens in der Testphase) und dein Script darf an dieser Stelle dann weiterlaufen.

Am Scriptende nicht vergessen diese Lockdatei zu löschen.

Bedenke aber ein Script kann man auf verschiedene Arten starten, du muss also in der Kommandozeile wirklich suchen.
Code:
/PATH/script.sh
./script.sh
bash /PATH/script.sh
sh script.sh
Wenn du es richtig machen willst, müsstest du auch bedenken, das man das Script eventuell irgendwann umbennen oder kopieren kann, und der LOCK soll dann trotzdem noch funktionieren auch wenn das Script in der Zwischenzeit einen anderen Namen hat, aber das währe dann schon Shell-Oberliega.

aussehen könnte ein Test ungefähr dann so (mal nur einfache Befehle verwendet)
Code:
LOCK=$(cat "$RUN_LOCK")
if cat /proc/"$LOCK"/cmdline 2>/dev/null | tr "\0" "\n" | grep "$0" > /dev/null
 then
     # Script wird schon ausgeführt
.......

Wobei von $0 nur der basename verwendetet werden sollte , aber auch irgend eine Shell sein könnte, und dann müßte anstatt dafür dann $1 genommen werden ............ usw. das ist dann schon die Oberliega ;)

robi
 
OP
OsunSeyi

OsunSeyi

Hacker
Vielen Dank, ich denke das wird so klappen.
Mir ist aber noch die Möglichkeit eingefallen, 'pstree' auszuwerten.
Die Ausgabe ist eindeutiger als 'ps aux', aber das 'wie' schwieriger...
Was ist denn der gängige Weg?
Große Programme wie 'Audacity' oder ein 'Seamonkey'-Profil lassen sich auch nur einmal aufrufen.
Ok, sind keine Scripte...
Naja, wenn der sicherste weg über eine Lockdatei und löschen mit der Funktion 'cleanupFiles' von framp geht, wird's das wohl sein.
 
Aus meiner Sicht ist das größte Problem, wenn das Script schnell 2x hintereinander gestartet wird.
Ich würde versuchen, eine Datei mit "touch" anzulegen und mit "tail -f datei & MYPID=$!" und
anschliessendem "fuser datei ... Check nach Pids != MYPID" andere Prozesse zu entdecken.
Natürlich darf man am Ende nicht vergessen, den tail ...& wieder abzuschiessen.

Haveaniceday
 
A

Anonymous

Gast
haveaniceday schrieb:
Aus meiner Sicht ist das größte Problem, wenn das Script schnell 2x hintereinander gestartet wird.
Ich glaube da kann ich dich beruigen, solange du das hintereinander startest läuft es hintereinander. Wenn du es schaffen würdest auf einer Mehrprozessormaschine paralell aus verschiedenen Shells heraus, könnte es das Problem geben das du nicht vorausbestimmen kannst welcher Prozess den Zuschlag bekommt. Aber das es da Probleme geben sollte, dass beide Prozesse der Meinung sind das sie beide laufen dürfen, ist wie ein Sechser im Lotto. Ich hatte noch keinen ;)
Alleine das Laden der Shell- und Prozessorumgebung in den Hauptspeicher dauert ein Vielfaches länger als die Interpretation und Ausführung der Befehle. Zumal das Filesystem den Zugriff auf diese Datei auch locken würde in dem Moment wenn einer der Prozesse da schreiben will.

Aber wenn das für dich das "größte Problem" ist, dann schau mal in die Manpage von lockfile
das noch vorschalten und es klappt auch dann zuverlässig wenn du 10000 Prozesse gleichzeig auf 10000 Prozessoren starten könntest, also wenn du jeden Monat einen Sechser im Lotto hast. ;)

robi
 
Oben