bashskript - solange programm läuft
-
Hallo,
versuche mich gerade an einem kleinen Bashskript.
Dieses startet ein Programm, und soll dann für jede minute die dieses läuft einmal ein ps loggen.
Bin jedoch totaler Bash Analphabet.Dies ist bisher mein Ansatz:
#!/usr/bin/bash command=$1 logfile=ramusage.log $command & line=$(ps -efyl | grep transcode |grep -v grep) echo $line valid=$(`echo $line | wc -l`) echo $valid while $( $valid > 0) do echo $line >> $logfile sleep 60 $line=$(ps -efyl | grep transcode |grep -v grep) $valid=$(echo $line | wc -l) done echo "done"
Innerhalb der Schleife allerdings kommt es zu problemen:
./ramusage.sh: 1: command not founddies müste die letzte Zeile sein, davor gibt es was ähnliches mit "S : command...".
Die letzten beiden zeilen sind also noch problematisch, sehe aber da irgendwie keinen FehlerAxo: Solaris8 als OS
Ist also wahrscheinlich nicht die modernste bash...
-
mach's so:
#!/bin/sh command=$1 logfile=ramusage.log $command & GET_CMD="ps -efyl | grep transcode |grep -v grep" line=$(${GET_CMD}) echo $line valid="`echo $line | wc -l`" echo $valid while test ${valid} -ne 0 ; do echo $line >> $logfile sleep 60 $valid="$(${GET_CMD} | wc -l)" done echo "done"
(Achte auf die entfertne $-Zeichen)
btw. die Erste Zeile würde ich zu #!/bin/sh ändern.
-
Eine vielleicht bessere Variante wäre:
#!/bin/sh $@ & PID="$(jobs -p)" while test -d /proc/${PID} ; do sleep 1 done echo "done"
-
supertux schrieb:
Eine vielleicht bessere Variante wäre:
#!/bin/sh $@ & PID="$(jobs -p)" while test -d /proc/${PID} ; do sleep 1 done echo "done"
Noch besser wär, die Variable $@ zu quoten, sonst passiert das hier:
$ cat foo.sh #!/bin/sh $@ $ ./foo.sh printf 'Ergebnis: %d\n' 42 Ergebnis:$
gegenüber:
$ cat foo.sh #!/bin/sh "$@" $ ./foo.sh printf 'Ergebnis: %d\n' 42 Ergebnis: 42 $
Falls das gesamte Kommando in $1 steht, führt vermutlich kein Weg an einem eval oder bash -c vorbei, d.h. zum Beispiel:
eval "$1" &
Schreibt man nur $1 auf einer Zeile, macht das word splitting nämlich sonst die Parameter des Befehls kaputt.
Anstatt $(jobs -p) kannst du auch $! nehmen, diese Spezialvariable enthält die PID des letzten Prozesses. Außerdem gibt es bei jobs noch andere Spezialvariablen, die mit % beginnen (siehe unten).
supertux schrieb:
btw. die Erste Zeile würde ich zu #!/bin/sh ändern.
Ich kenne #!/bin/bash als übliche erste Zeile für bash-Skripte. Ich bin mir nicht so sicher, ob man sich bei #!/bin/sh tatsächlich darauf verlassen kann, dass $(...), jobs und andere Bash-builtins existieren.
Eigentlich hatte ich gehofft, dass es eine Lösung mit trap auf SIGCHLD gibt. Aber das scheint nicht so einfach zu gehen, weil der SIGCHLD-trap-Handler in Bash die PID des childs nicht bekommt, das das Signal generiert hat.
Eine andere Lösung gäbe es aber:
#!/bin/bash set -m "$@" & while kill -0 %1 &>/dev/null; do echo -n . sleep 1 done echo "done."
Der Vorteil daran ist, dass es nicht /proc verwendet und keine PIDs. Damit können keine race conditions auftreten bei neu vergebenen PIDs. kill ist ein bash-builtin, also sehr schnell. Das Signal 0 bedeutet "prüfe nur, ob der angegebene Job in der Lage ist Signale zu empfangen", entspricht hier also einem "prüfe, ob der Job noch lebt". Die bash-Option -m ist notwendig, damit job control im Skript korrekt funktioniert.
-
Christoph schrieb:
supertux schrieb:
btw. die Erste Zeile würde ich zu #!/bin/sh ändern.
Ich kenne #!/bin/bash als übliche erste Zeile für bash-Skripte. Ich bin mir nicht so sicher, ob man sich bei #!/bin/sh tatsächlich darauf verlassen kann, dass $(...), jobs und andere Bash-builtins existieren.
Nein, da hast Du natürlich Recht.
Auch wenn es unter vielen GNU/Linux-Distros üblich ist, dass /bin/sh einfach nur ein Symlink auf /bin/bash ist, handhaben andere Distros und diverse BSDs das nicht so. Da ist es einfach nur lästig, wenn ein vor Bashismen strotzendes Programm einen Bourne-Shell-Shebang hat. (Selbst wenn /bin/sh häufig eine ash ist, die $() und ähnliche Job-Control-Features wie ksh hat.)
-
Ich mag mich daran erinnern irgendwo gelesen zu haben, dass #!/bin/sh dafür sorgt, die Standard-Shell des Benutzers zu verwenden. Es ist schon lange her, dass ich das gelesen habe, deswegen weiß ich nicht mehr wo und ob's überhaupt stimmt.
-
supertux schrieb:
Ich mag mich daran erinnern irgendwo gelesen zu haben, dass #!/bin/sh dafür sorgt, die Standard-Shell des Benutzers zu verwenden. Es ist schon lange her, dass ich das gelesen habe, deswegen weiß ich nicht mehr wo und ob's überhaupt stimmt.
Das ist nicht der Fall, würde ich sagen. Einige user in /etc/passwd haben bei mir /bin/false als Shell eingetragen, weil sie keine interaktive Shell brauchen. Unter diesen user-ids kann man aber trotzdem Shell-Skripte ausführen, bei denen #!/bin/sh in der ersten Zeile steht. Das habe ich mit sudo getestet.
-
daran habe ich gar nicht gedacht, dann habe ich das ganze falsch in Erinnerung gehabt.
-
Naja, es gibt ein paar komische Leute, die der Ansicht sind, man solle /bin/sh auf die Lieblingsshell versymlinken. Das halte ich persönlich für großen Blödsinn und man läuft damit Gefahr, viele Sachen kaputtzumachen, wenn die eigene Lieblingsshell nicht Bash oder eine Bourne-Shell ist.
Außerdem gibt es für solche Späße ja den Login-Shell-Eintrag in /etc/passwd. Der Shebang legt einfach nur (per Absolutpfad) den Interpreter fest; die Login-Shell des Users wird also ignoriert, ich nehme an, dass der von Dir gelesene Text sich auf genau das oben beschriebene Verhalten bezieht.