PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [SH] Prozess beendet sich nicht mehr automatisch



AS2E
12-12-2010, 14:33
Ich habe das folgende Script und möchte damit immer aktuell die Daten eines Prozesses aus /proc/<pid>/status in ein File schreiben und das so lange wie der Prozess ausgeführt wird.


#!/bin/sh
lang=$1
code=$2
#
#Check the language
if [ "$lang" = "jruby" ]; then
jruby $code &
#Is the process still running?
until [ $(ps -e | grep -c $!) -ne 0 ]
do
cat /proc/$!/status >> /opt/data.txt
done
elif [ "$lang" = "clojure" ]; then
echo blabla
else
echo "Ungueltige Eingabe"
fi


Ohne die Schleife funktioniert es super. Um nun aber zu prüfen ob der Prozess noch aktiv ist, habe ich eine Schleife hinzugefügt. Das Problem ist jetzt, dass der Prozess den ich aufrufe, sich nicht mehr selbst beendet. Der fällt nun nach der Ausführung in sowas wie einen Sleep-Modus bis man ihn manuell killt. Das führt natürlich dazu, dass auch meine Schliefe sich nicht mehr selbst beendet.

Hat jemand eine Idee wieso das so ist und was man dagegen machen könnte? Ich hab selbst leider keine allzu grosse Erfahrung mit Shell-Scripts.

Vielen Dank!

John W
12-12-2010, 15:22
Hast du mal versucht, ein sleep einzubauen? Zudem würde ich statt "$(ps -e | grep -c $!)" besser "ps $!" schreiben. Die if-elif-else-Konstruktion könntest du auch noch durch ein case-Konstrukt ersetzen.

AS2E
12-12-2010, 16:04
Danke für die Verbesserungsvorschläge. Aber ich wenn ich "$(ps -e | grep -c $!)" einfach durch "ps $!" ersetzten funktioniert das Script nicht mehr (too many arguments). Eigentlich auch logisch, das Resultat von "ps -e | grep -c $!" ist ja auch nicht das gleiche wie dasjenige von "ps $!".

Was meinst du genau mit sleep einbauen. Mir ist jetzt nicht wirklich klar, wo mir ein sleep etwas nützen könnte.

John W
12-12-2010, 16:54
Ich kann mir gut vorstellen, dass der Prozess nicht beendet werden kann, wenn er dauernd inspiziert wird, daher dachte ich, dass folgender Code vl funktioniert:


while ps $! > /dev/null
do
cat /proc/$!/status >> /opt/data.txt
sleep 1
done
PS: Ich hab vergessen zu erwähnen, dass die Schleifenlogik dabei umgedreht werden muss und dass test ([ ... ]) dann auch nicht mehr benötigt wird.

AS2E
12-12-2010, 17:22
Cool. Funktioniert bestens. Vielen Dank.

Weisst du zufällig auch, wie ich nur bestimmte Zeilen aus einer Datei auslesen kann. Mit "cat /proc/$!/status >> /opt/data.txt" wird ja sozusagen immer die ganze status-Datei in meine "data.txt" Datei kopiert. Ist es irgendwie auch möglich z.B. nur die Zeilen 10-15 zu kopieren?

John W
12-12-2010, 17:26
Einzelne Zeilenbereiche kannst du mit sed ausgeben lassen:


sed -n '10,15p' /proc/$!/status >> /opt/data.txt

Mit sed kannst du statt Zeilenangaben als Bereich auch reguläre Ausdrücke benutzen, z.B. "sed -n '/start/,/ende/p'". Wichtig ist der Parameter -n, da sonst alle Zeilen ausgegeben würden und Zeilen im Bereich doppelt.

AS2E
13-12-2010, 17:44
Vielen Dank. Funktioniert alles soweit. Ich möchte mein Script jetzt aber noch etwas erweitern in dem ich die Prozessdaten welche "top" ausliest in ein anderes File schreibe. Ich habe also die folgenden Zeilen unterhalb der Schleife hinzugefügt.



jruby $code &
top -p $! -b -d 01.00 >> /opt/data/jruby.top

Nun hat top ja die Eigenheit auch weiterzulaufen, wenn der Prozess den ich mit -p angebe gar nicht mehr läuft. Wie kann ich jetzt also prüfen ob mein Prozess noch läuft und falls das nicht mehr der Fall ist, wie kann ich top dann abbrechen?

Ich nehme an, da brauche ich wieder die gleiche Schliefe wie für das vorherige Problem auch um zu prüfen ob der Prozess noch läuft. Da kommt dann ein kill-Befehl rein. Das geht aber wahrscheinlich nicht einfach so, weil top einen neuen Prozess startet. Wenn ich also $! in die Schleifenbedingung schreibe, prüfe ich ob top noch läuft, nicht ob der andere Prozess noch läuft. Hat dafür jemand einen Lösungsvorschlag?

John W
13-12-2010, 18:23
Um die Prozessnummer zu erhalten, würde ich das Script abändern:
Nachdem der Prozess gestartet wurde, speicherst du die PID ab und gibt die per acho auf stdout aus.
Dein Script rufst du dann nicht mehr selbst auf, sondern machst das so:

top -p "$(script)" -b -d 01.00 >> /opt/data/jruby.top

AS2E
14-12-2010, 16:17
Um die Prozessnummer zu erhalten, würde ich das Script abändern:
Nachdem der Prozess gestartet wurde, speicherst du die PID ab und gibt die per acho auf stdout aus.
Dein Script rufst du dann nicht mehr selbst auf, sondern machst das so:


Ich kann dir leider nicht 100%ig folgen.

Also Prozess starten, PID speichern (in eine Variable nehm' ich an?) und per echo ausgeben. Sowas?



jruby $code &
pid0=$! &
echo $pid0


Das führt schon mal dazu, dass sich mein Programm nicht mehr beendet. Und das Script rufe ich anschliessend mit dem Top-Befehl auf? Ich mir ist ehrlich gesagt überhaupt nicht klar, wie das funktionieren sollte. Wäre echt dankbar, wenn du mir das noch etwas detaillierter erklären könntest. Hab wie gesagt noch nicht viel Erfahrung das scripten angeht.

John W
14-12-2010, 16:22
Nein, etwa so:

#!/bin/sh
lang=$1
code=$2
#
#Check the language
if [ "$lang" = "jruby" ]; then
jruby $code &
PID=$!
echo $PID
#Is the process still running?
while ps $PID > /dev/null
do
sed -n '10,15p' /proc/$!/status >> /opt/data.txt
sleep 1
done
elif [ "$lang" = "clojure" ]; then
echo blabla >&2
else
echo "Ungueltige Eingabe" >&2
fi
Wichtig ist, dass du dabei nichts auf stdout ausgibst, sonst macht


top -p "$(script)" -b -d 01.00 >> /opt/data/jruby.top

Unsinn, weil $(script) nicht mehr nur die Pid ausgeben würde.
Im obigen Code habe ich die Meldungen auf stderr oder nach /dev/null umgeleitet, es sollte so also funktionieren.

AS2E
14-12-2010, 18:47
Hm, funktioniert bei mir leider so nicht. Hier mal mein Script wies im Moment aussieht, vielleicht kannst du ja einen Fehler erkennen.


#!/bin/sh
lang=$1
code=$2
#
#Check the language
case $lang in
jruby)
#Get Memory Data
jruby $code &
PID=$!
echo $PID
#Is the process still running?
while ps $PID > /dev/null
do
sed -n '11,20p' /proc/$!/status >> /opt/data/jruby.memory
echo '-----------------------' >> /opt/data/jruby.memory
sleep 1
done
;;
clojure)
echo blabla >&2 ;;
scala)
;;
*)
echo "Ungueltige Eingabe" >&2
esac


Aufgerufen hab ich das ganze mit jetzt wie folgt.


top -p "$(./get_performance_data.sh jruby /opt/samples/Test.rb)" -b -d 01.00 >> opt/data/jruby.top

Da steht dann der folgende Fehler:

top: unknown argument '

Ich hab schon daran gedacht, dass es vielleicht aufgrund meiner zusätzlichen Parameter nicht geht. Aber ohne die kann mein Script ja auch nicht funktionieren.

John W
14-12-2010, 19:05
"jruby $code &" wird wohl dran schuld sein - ersetz das mal durch "jruby $code >&2 &", dann werden Ausgaben vom Ruby-Code auch nach stderr geschrieben.

AS2E
14-12-2010, 22:22
Jetzt gibts keinen Fehler mehr aber leider auch keine Daten. So werden nun nur die Spaltenüberschriften ins File geschrieben, eigentlich das was top macht, wenn der überwachte Prozess nicht aktiv ist.

Ich hab mir inzwischen überlegt, ob es vielleicht einfacher wäre das ohne den top-Befehl zu machen. Top muss ja seine Daten grundsätzlich auch von irgendwo beziehen. Wahrscheinlich auch irgend ein File im procfs. Wenn man herausfinden könnte wo sich diese Daten befinden, könnte man sie direkt von dort auslesen. Ich werd morgen mal etwas googeln, vielleicht find ichs ja raus oder evtl. weiss es hier sogar jemand. Das Resultat wäre evtl. sogar besser, da ich eh nicht alle Spalten brauche die top ausgibt.

AS2E
16-12-2010, 18:39
Hab herausgefunden, das man mit ps ebenfalls ähnliche Daten auslesen kann. Ich habs jetzt wie folgt gelöst (falls Interesse vorhanden).


random=tmp$(date +%d%m%Y_%H%M%S)
jruby $code &
while ps $! > /dev/null
do
ps -p $! -o user,pid,%cpu,c,time >> /opt/data/$random
sleep 1
done
sed '3~2d' /opt/data/$random >> /opt/data/jruby.cpu
rm /opt/data/$random

John W
16-12-2010, 18:49
Empfehlung:
random=tmp$(date +%d%m%Y_%H%M%S)
durch
random="$(mktemp --tmpdir=/tmp/jrubyXXXXXX)"
ersetzen, dein ersteres ist anfällig gegen Race-Conditions.