2009-03-05 21 views
418

ich ein Skript 'myscript' haben, die die folgende Ausgänge:mehrzeilige Ausgabe in eine Bash Variable Capturing

abc 
def 
ghi 

in einem anderen Skript, nenne ich:

declare RESULT=$(./myscript) 

und $RESULT die bekommt Wert

Gibt es eine Möglichkeit, das Ergebnis entweder mit den Zeilenumbrüchen oder mit '\ n' Zeichen so zu speichern, ich c eine Ausgabe mit 'echo -e'? Eigentlich

+1

es überrascht mich. hast du nicht $ (cat ./myscipt)? sonst hätte ich erwartet, dass es versucht Befehle auszuführen abc, def und ghi –

+0

@litb: ja, nehme ich an; Sie können auch $ (<./ meinscript) verwenden, wodurch die Ausführung eines Befehls vermieden wird. –

+2

(NB: die beiden obigen Kommentare beziehen sich auf eine Revision der Frage, die begann _Ich habe ein Skript 'myscript', das folgendes enthält, was zu den Fragen führte. Die aktuelle Überarbeitung der Frage (_Ich habe ein Skript "myscript", das das folgende ausgibt, macht die Kommentare überflüssig. Die Überarbeitung stammt jedoch vom 2011-11-11, lange nachdem die beiden Kommentare gemacht wurden. –

Antwort

784

, RESULT enthält, was Sie wollen - demonstrieren:

echo "$RESULT" 

Was zeigen Sie, was Sie erhalten von:

echo $RESULT 

bemerkt Wie in den Kommentaren, ist der Unterschied dass (1) die doppelt zitierte Version der Variablen (echo "$RESULT") den internen Abstand des Werts genau so erhält, wie er in der Variablen dargestellt wird - Zeilenumbrüche, Tabulatoren, mehrere Leerzeichen und all - wherea s (2) Die nicht-quoted Version (echo $RESULT) ersetzt jede Folge von einem oder mehreren Leerzeichen, Tabulatoren und Zeilenumbrüchen durch ein einzelnes Leerzeichen. So behält (1) die Form der Eingabevariablen bei, während (2) eine potentiell sehr lange einzelne Ausgabezeile mit "Wörtern" erzeugt, die durch einzelne Leerzeichen getrennt sind (wobei ein Wort eine Folge von Nicht-Leerzeichen ist; dort needn keine alphanumerischen Zeichen in irgendeinem der Wörter sein.

+59

@troelskn: Der Unterschied ist, dass (1) die doppelt zitierte Version von Die Variable behält den internen Abstand des Werts genau so bei, wie er in der Variablen, den Zeilenumbrüchen, den Tabs, mehreren Leerzeichen und allen anderen Elementen dargestellt wird. Dagegen ersetzt die nicht abgekürzte Version jede Folge von einem oder mehreren Leerzeichen, Tabulatoren und Zeilenumbrüchen durch ein einzelnes Leerzeichen. So behält (1) die Form der Eingabevariablen bei, während (2) eine potentiell sehr lange einzelne Ausgabezeile mit "Wörtern" erzeugt, die durch einzelne Leerzeichen getrennt sind (wobei ein Wort eine Folge von Nicht-Leerzeichen ist; dort needn werde nicht sein alphanumerische Zeichen in einem der Wörter). –

+17

Um die Antwort einfacher zu verstehen: Die Antwort sagt, dass Echo "$ RESULT" Newline beibehält, während Echo $ RESULT dies nicht tut. –

+0

In bestimmten Situationen können Zeilenvorschübe und führende Leerzeichen nicht beibehalten werden. – CommaToast

72

Ein weiterer Fehler mit diesem ist, dass command substitution - $() - Zeilenumbrüche Zeilenumbrüche. Wahrscheinlich nicht immer wichtig, aber wenn Sie wirklich erhalten wollen genau was ausgegeben wurde, werden Sie eine andere Linie und einige zitieren verwenden müssen:

RESULTX="$(./myscript; echo x)" 
RESULT="${RESULTX%x}" 

Dies ist besonders wichtig, wenn Sie handle all possible filenames wollen (um zu vermeiden undefiniertes Verhalten wie das Arbeiten mit der falschen Datei).

+3

+1 Dies ist wahr und Was fehlte JonathanLefflers Antwort! –

+3

Ich musste eine Weile mit einer defekten Shell arbeiten, die die letzte neue Zeile nicht aus der [Befehlsersetzung] entfernt hat (http://www.gnu.org/software/bash/manual/bash.html#Command-Substitution) (Es ist _nicht_ [Prozesssubstitution] (http://www.gnu.org/software/bash/manual/bash.html#Process-Substitution)), und es hat fast alles kaputt gemacht. Zum Beispiel, wenn du '' pwd = 'pwd'; ls $ pwd/$ file'', Sie haben einen Zeilenumbruch vor dem '/', und das Einschließen des Namens in Anführungszeichen hat nicht geholfen. Es wurde schnell behoben. Dies war 1983-5 Zeitrahmen auf ICL Perq PNX; Die Shell hatte nicht $ PWD als eingebaute Variable. –

0

Wie wäre es damit, es liest jede Zeile zu einer Variablen und das kann anschließend verwendet werden! sagen myscript Ausgabe in eine

myscript_output genannt Datei umgeleitet wird
awk '{while ((getline var < "myscript_output") >0){print var;} close ("myscript_output");}' 
+4

Nun, das ist keine Bash, das ist awk. – vadipp

12

Neben dem durch @ gegebene Antwort l0b0 Ich hatte gerade die Situation, wo ich brauchte, sowohl durch das Skript jede Hinter newlines Ausgabe zu halten und Kontrolle der Rückgabecode des Skripts Und das Problem mit der Antwort von l0b0 ist, dass das "Echo x" $ zurückgesetzt hat? auf Null zurück ... so konnte ich mit dieser sehr schlauen Lösung kommen:

RESULTX="$(./myscript; echo x$?)" 
RETURNCODE=${RESULTX##*x} 
RESULT="${RESULTX%x*}" 
11

Wenn Sie in bestimmten Linien interessiert sind, einen Ergebnis-Array nutzen:

declare RESULT=($(./myscript)) # (..) = array 
echo "First line: ${RESULT[0]}" 
echo "Second line: ${RESULT[1]}" 
echo "N-th line: ${RESULT[N]}" 
+2

Wenn in den Zeilen Leerzeichen vorhanden sind, werden Felder (Inhalte zwischen Leerzeichen) anstelle von Zeilen gezählt. – Liam

+3

Dies funktioniert nicht auf Dash oder POSIX Shell – gpanda

+1

Sie würden 'readarray' und Prozesssubstitution anstelle von Befehlsersetzung verwenden:' reararray -t RESULT <<(./myscript> '. – chepner

0

Nach Ich versuchte die meisten Lösungen hier, das einfachste, was ich fand, war das Offensichtliche - eine temporäre Datei zu verwenden. Ich bin nicht sicher, was Sie mit Ihrer mehrzeiligen Ausgabe machen wollen, aber Sie können dann zeilenweise mit Lesen umgehen.Über das einzige, was Sie nicht wirklich tun können, ist es, alles in die gleiche Variable zu stecken, aber für die meisten praktischen Zwecke ist dies viel einfacher zu handhaben.

./myscript.sh > /tmp/foo 
while read line ; do 
    echo 'whatever you want to do with $line' 
done < /tmp/foo 

Schnell Hack es die angeforderte Aktion auszukommen:

result="" 
./myscript.sh > /tmp/foo 
while read line ; do 
    result="$result$line\n" 
done < /tmp/foo 
echo -e $result 

Hinweis dies fügt eine zusätzliche Zeile. Wenn du daran arbeitest, kannst du damit umgehen, ich bin einfach zu faul.


EDIT: Während dieser Fall sehr gut funktioniert, Menschen lesen sollten sich bewusst sein, dass Sie einfach Ihre stdin innerhalb der while-Schleife quetschen können, so dass Sie ein Skript geben, die eine Zeile, klare stdin laufen wird, und Ausfahrt . Wie ssh wird das tun, denke ich? Ich habe es gerade erst gesehen, andere Codebeispiele hier: https://unix.stackexchange.com/questions/24260/reading-lines-from-a-file-with-bash-for-vs-while

Noch einmal! Diesmal mit einem anderen Dateihandle (stdin, stdout, stderr sind 0-2, also können wir & 3 oder höher in bash verwenden).

result="" 
./test>/tmp/foo 
while read line <&3; do 
    result="$result$line\n" 
done 3</tmp/foo 
echo -e $result 

Sie können auch mktemp verwenden, aber dies ist nur ein schnelles Codebeispiel. Die Verwendung für mktemp sieht so aus:

filenamevar=`mktemp /tmp/tempXXXXXX` 
./test > $filenamevar 

Verwenden Sie dann $ filenamevar wie Sie den tatsächlichen Namen einer Datei. Muss wohl hier nicht erklärt werden aber jemand hat sich in den Kommentaren beschwert.

+0

Ich habe auch andere Lösungen ausprobiert, mit deinem ersten Vorschlag habe ich endlich mein Skript funktioniert –

+1

Downvote: Das ist übermäßig komplex und vermeidet mehrere häufige ['bash' Fallen] (http://mywiki.wooledge.org/BashPitfalls) . – tripleee

+0

Ya jemand erzählte mir über die seltsame stdin Dateihandle Problem neulich und ich war wie "wow". Lass mich etwas wirklich schnell hinzufügen. – user1279741

Verwandte Themen