2016-05-13 7 views
1

Dieses erfundene Bash-Skript demonstriert das Problem.Bash-Schleife stoppt nach der ersten Iteration, wenn die Subshell aufgerufen wird

#!/bin/bash 
while read -r node ; do 
    echo checking $node for Agent; 
     PID=$(ssh $node ""ps -edf | grep [j]ava | awk '{print $2}'"") 
     echo $PID got to here. 
done < ~/agents_master.list 

agents_master.list enthält 1 Server pro Zeile:

server1 
server2 
server3 

die nur gibt die folgenden:

checking server1 for Agent 
Authorized use only 
25176 got to here 

Server 2 und 3 ist nicht einmal durch die auf Bildschirm angezeigt out Linie echo checking $node...

Wenn ich die Zeile PID=$(.... dann th ausmerken e während vervollständigt die ganze agents_master.list Datei korrekt ...

checking server1 for Agent 
got to here 
checking server2 for Agent 
got to here 
checking server3 for Agent 
got to here 

Vom googeln ich getan habe, es klingt wie dies dem Subshell zusammenhängt, dass $(...) schafft, aber ich verstehe nicht, warum es ist Dadurch wird die Schleife beim ersten Server angehalten, .

Ja, dieser Code könnte neu geschrieben werden, aber ich bin daran interessiert, dieses Verhalten von bash zu verstehen und warum dies für die Zukunft geschieht.

+0

'PID = $ (ps -edopid =, Befehl = | awk '/ [j] ava/{print $ 1}') 'erspart dir einen Pfeifen- und Verschwendungsprozess. Angenommen, Sie sind in Linux. – ghoti

Antwort

4

Das Problem - eines der Probleme - ist, dass ssh Stdin an den Remote-Server weiterleitet. Der Befehl, den Sie auf dem Remote-Server ausführen (ps -edf, siehe unten), verwendet nicht die Standardeingabe, aber ssh wird nur für den Fall weiterleiten, was er liest. Als Konsequenz bleibt nichts mehr für read zu lesen, also endet die Schleife.

Um dies zu vermeiden, verwenden Sie ssh -n (oder leiten Sie die Eingabe selbst an /dev/null um, was die Option -n tut).

Es gibt ein paar andere Probleme, die die Ausführung Ihrer Skripte nicht stören.

Zuerst habe ich keine Ahnung, warum Sie "" in

ssh $node ""ps -edf | grep [j]ava | awk '{print $2}'"" 

Die "" „erweitert“ auf eine leere Zeichenfolge verwenden, so ist die oben effektiv identisch mit

ssh $node ps -edf | grep [j]ava | awk '{print $2}' 

das bedeutet, dass die grep und awk Befehle werden auf dem lokalen Host ausgeführt; Die Ausgabe des Befehls ps wird von ssh an den lokalen Host weitergeleitet. Das ändert nichts, obwohl es die Klammern in [j]ava überflüssig macht, da die grep nicht in der Prozessliste angezeigt wird, da sie nicht auf dem Host läuft, auf dem die ps ausgeführt wird. In der Tat ist es eine gute Sache, dass die Klammern redundant sind, da sie möglicherweise nicht in dem Befehl vorhanden sind, wenn sich eine Datei mit dem Namen java in Ihrem aktuellen Arbeitsverzeichnis befindet. Sie sollten dieses Argument wirklich zitieren.

Ich nehme an, was Sie wollten, war die gesamte Pipeline auf dem entfernten Rechner zu laufen, in dem Fall, dass Sie versucht haben könnten:

ssh $node "ps -edf | grep [j]ava | awk '{print $2}'" 

und fand, dass es nicht funktioniert hat.Es hätte nicht funktioniert, weil die $2 im awk-Befehl zu was auch immer $2 in Ihrer aktuellen Shell erweitert wird; Die $2 ist nicht geschützt durch innere einfache Anführungszeichen. Soweit Bash betroffen ist, ist $2 nur Teil einer doppelten Zeichenfolge in Anführungszeichen. (Und es würde auch das Problem des Arguments auf grep nicht auf dem Remote-Host zitiert werden, so dass Sie Probleme haben, wenn es eine Datei mit dem Namen java im Home-Verzeichnis auf dem Remote-Host ist.

Also was Sie eigentlich will, ist

ssh -n $node 'ps -edf | grep "[j]ava" | awk "{print \$2}"' 

schließlich nicht PID als Name einer Shell-Variablen verwenden. Variablennamen in Großbuchstaben sind in der Regel reserviert, und es ist gefährlich nahe an BASHPID und PPID, die spezifische bash Variablen Ihre eigenen Shell-Variablen sollten, wie in jeder anderen Programmiersprache auch, Kleinbuchstaben haben

+0

danke sehr sehr für die ausführliche Antwort. – sparco1500

+0

Ehrfürchtig. Ich kann nur meine löschen :) +1 – Amadan

+0

Bessere Frage und Antwort dann die "doppelte" Frage. – Doug