Wie kann ich dafür sorgen, dass der Bash-Backtick-Operator Zeilenumbrüche in der Ausgabe beibehält?

36

Gibt es eine Möglichkeit, Bash zu veranlassen, keine Zeilenumbrüche in der Backtick-Ersetzung zu essen?

Beispielsweise:

var=`echo line one && echo line two`
echo $var

line one line two

Was ich will ist

var=`echo line one && echo line two` # plus some magic
echo $var

line one
line two
schleichendes Gift
quelle

Antworten:

54

Es ist kein Problem bei der Substitution von Backticks, sondern bei echo; Sie müssen die Variable in Anführungszeichen setzen, damit die Steuerzeichen funktionieren:

$ var=`echo line one && echo line two`
$ echo "$var"
line one
line two
cYrus
quelle
Bash entfernt also Zeilenumbrüche, während eine Variable auf dem Befehlspfand erweitert wird? Und dieses Verhalten kann deaktiviert werden, indem die Variable in Anführungszeichen gesetzt wird?
Slowpoison
7
bashführt Parameter Expansion vor der Ausführung eines Befehls unter Angabe ist notwendig , um zu informieren , bashdass Sie einen einzelnen String drucken möchten , und nicht 4 Worte ( line, one, lineund two). Versuchen Sie: echo a <many spaces> bund echo "a <many spaces> b". Schauen Sie sich auch diese Antwort an .
CYRUS
5

Auch wenn @cyrus richtig ist - es beantwortet nicht die ganze Frage und es gibt keine Erklärung dafür, was passiert.

Lass uns also durchgehen.

Zeilenumbrüche in Zeichenfolge

Bestimmen Sie zunächst die zu erwartende Bytereihenfolge:

$ { echo a; echo b; } | xxd
0000000: 610a 620a                                a.b.

Verwenden Sie jetzt Command Substitution (Abschnitt 3.5.4), um zu versuchen, diese Byte-Sequenz zu erfassen:

$ x=$( echo a; echo b; )

Führen Sie dann ein einfaches Echo durch, um die Bytesequenz zu überprüfen:

$ echo $x | xxd
0000000: 6120 620a                                a b.

Es scheint also, dass die erste Zeile durch ein Leerzeichen ersetzt wurde und die zweite Zeile intakt blieb. Aber wieso ?

Schauen wir uns an, was hier tatsächlich passiert:

Zunächst führt bash die Shell-Parametererweiterung aus (Abschnitt 3.5.3).

Das Zeichen '$' führt eine Parametererweiterung, eine Befehlssubstitution oder eine arithmetische Erweiterung ein. Der zu erweiternde Parametername oder das zu erweiternde Symbol kann in geschweiften Klammern angegeben werden, die optional sind, aber dazu dienen, die zu erweiternde Variable vor Zeichen zu schützen, die unmittelbar darauf folgen und als Teil des Namens interpretiert werden könnten.

Dann führt bash die Wortteilung durch (Abschnitt 3.5.7)

Die Shell überprüft die Ergebnisse der Parametererweiterung, der Befehlssubstitution und der arithmetischen Erweiterung, die bei der Wortteilung nicht in doppelten Anführungszeichen stehen.

Die Shell behandelt jedes Zeichen von $ IFS als Trennzeichen und teilt die Ergebnisse der anderen Erweiterungen in Wörter für diese Zeichen auf. Wenn IFS nicht gesetzt ist oder sein Wert genau ist, ...

Als nächstes behandelt bash es als einfachen Befehl (Abschnitt 3.2.1)

Ein einfacher Befehl ist die Art von Befehl, die am häufigsten vorkommt. Es ist nur eine Folge von Wörtern, die durch Leerzeichen getrennt sind und durch einen der Steueroperatoren der Shell abgeschlossen werden (siehe Definitionen). Das erste Wort gibt im Allgemeinen einen auszuführenden Befehl an, wobei die restlichen Wörter die Argumente dieses Befehls sind.

Die Definition von Leerzeichen (Abschnitt 2 - Definitionen)

leer Ein Leerzeichen oder ein Tabulatorzeichen.

Schließlich ruft bash den internen Befehl echo (Abschnitt 4.2 - Bash Builtin Commands) auf

... Geben Sie die durch Leerzeichen getrennten Argumente aus, die mit einem Zeilenumbruch abgeschlossen werden. ...

Zusammenfassend werden die Zeilenumbrüche durch Word Splitting entfernt, und das Echo erhält zwei Argumente, "a" und "b", und gibt sie dann getrennt durch Leerzeichen aus und endet mit einem Zeilenumbruch.

Wenn Sie das tun, was @cyrus vorgeschlagen hat (und die Newline von Echo mit -n unterdrücken), ist das Ergebnis besser:

$ echo -n "$x" | xxd
0000000: 610a 62                                  a.b

Zeilenumbrüche am Ende der Zeichenfolge

Es ist immer noch nicht perfekt, die nachgestellte Newline ist weg. Kommandosubstitution näher betrachten (Abschnitt 3.5.4) :

Bash führt die Erweiterung durch, indem der Befehl ausgeführt und die Befehlsersetzung durch die Standardausgabe des Befehls ersetzt wird, wobei alle nachfolgenden Zeilenumbrüche gelöscht werden.

Nun, da klar ist, warum der Zeilenumbruch wegfällt, kann man sich täuschen, ihn zu behalten. Fügen Sie dazu am Ende eine zusätzliche Zeichenfolge hinzu und entfernen Sie diese, wenn Sie die Variable verwenden:

$ x=$( echo a; echo b; echo -n extra )
$ echo -n "${x%extra}" | xxd
0000000: 610a 620a                                a.b.

TL; DR

Fügen Sie einen zusätzlichen Teil am Ende der Ausgabe hinzu und zitieren Sie Variablen:

$ cat /no/file/here 2>&1 | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865  cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65  re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a        or directory.
$ cat /no/file/here 2>&1 | cksum
3561909523 46
$ 
$ var=$( cat /no/file/here 2>&1; rc=${?}; echo extra; exit ${rc})
$ echo $?
1
$ 
$ echo -n "${var%extra}" | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865  cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65  re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a        or directory.
$ echo -n "${var%extra}" | cksum
3561909523 46
Iwan Aucamp
quelle
0

Ich hätte meinen kleinen Zusatz in einen Kommentar zur Antwort von cYrus eingefügt, aber ich kann noch keinen Kommentar zu Antworten abgeben, die ich denke. Also werde ich einen Teil von Cyrus 'Antwort der Vollständigkeit halber kopieren.

Was in der ersten Zeile Ihres Codes passiert, ist, dass die Backticks-Ersetzung tatsächlich die nachgestellten Zeilenumbrüche der Ausgabe des ersetzten Befehls auffrisst, wie dokumentiert . Aber es frisst nicht den Zeilenumbruch zwischen Ihren beiden Zeilen.

In der zweiten Codezeile wird das Echo mit zwei Argumenten ausgeführt, der ersten und der zweiten. Wenn Sie die erweiterte Variable in Anführungszeichen setzen, wird Folgendes behoben: echo "$var"Dadurch wird die neue Zeile zwischen Zeile eins und Zeile zwei beibehalten. Und echofügt standardmäßig eine nachgestellte Zeile hinzu, damit alles in Ordnung ist.

Wenn Sie nun alle nachgestellten Zeilenumbrüche in der Ausgabe einer Befehlsersetzung beibehalten möchten, können Sie eine weitere Zeile zur Ausgabe hinzufügen, die Sie nach der Befehlsersetzung entfernen können (siehe hier) .

Gaston
quelle