Mehrzeilige Syntax zum Weiterleiten eines Heredocs; ist das tragbar?

132

Ich bin mit dieser Syntax vertraut:

cmd1 << EOF | cmd2
text
EOF

aber gerade entdeckt, dass Bash mir erlaubt zu schreiben:

cmd1 << EOF |
text
EOF
cmd2

(Der Heredoc wird als Eingabe für cmd1 verwendet, und die Ausgabe von cmd1 wird an cmd2 weitergeleitet.) Dies scheint eine sehr merkwürdige Syntax zu sein. Ist es tragbar?

William Pursell
quelle
Ich bin hierher gekommen, um einen guten Weg zu finden, dies in mehrere Zeilen aufzuteilen : big-long-command1 with lots of args << EOF | big-long-command2 with lots of args. Die "ungerade Syntax" scheint der beste Weg zu sein.
PaulC
Ein praktischer Anwendungsfall hierfür ist, wenn Sie versuchen, eine durch Leerzeichen getrennte Tabelle in eine durch Tabulatoren getrennte Tabelle zu konvertieren, damit Sie sie in Google Spreadsheets einfügen können. Sie müssen keine temporäre Datei erstellen.
Sridhar Sarnobat
Der erste hat bei mir in Z-Shell nicht funktioniert. Ich mag den zweiten nicht, weil er den | entfremdet Aus dem Befehl geht die Redewendung (?) von Shell-Pipelines verloren.
Sridhar Sarnobat

Antworten:

104

Ja, der POSIX-Standard erlaubt dies. Nach der Version 2008:

Das Hier-Dokument wird als ein einzelnes Wort behandelt, das nach dem nächsten beginnt <newline>und fortgesetzt wird, bis eine Zeile nur das Trennzeichen und a enthält <newline>, ohne <blank>dazwischen liegende Zeichen. Dann beginnt das nächste Dokument hier, falls es eines gibt.

Und enthält dieses Beispiel für mehrere "Hier-Dokumente" in derselben Zeile:

cat <<eof1; cat <<eof2
Hi,
eof1
Helene.
eof2

Es ist also kein Problem, Umleitungen oder Pipes durchzuführen. Ihr Beispiel ähnelt ungefähr so:

cat file |
cmd

Die Shell-Grammatik (weiter unten auf der verlinkten Seite) enthält die folgenden Definitionen:

pipe_sequence    :                             command
                 | pipe_sequence '|' linebreak command

newline_list     :              NEWLINE
                 | newline_list NEWLINE
                 ;
linebreak        : newline_list
                 | /* empty */

Auf ein Pipe-Symbol kann also ein Zeilenende folgen und dennoch als Teil einer Pipeline betrachtet werden.

Ned Deily
quelle
26

Ja, es ist in der POSIX-Shell-Grammatik. Sie können auch mehr als ein here-doc für denselben Befehl haben (einige andere Beispiele verwenden zwei catAufrufe, aber dies funktioniert auch):

cat <<EOF1 <<EOF2
first here-doc
EOF1
second here-doc
EOF2

Dies ist erfunden (unter Verwendung von 2 here-docs für stdin), aber wenn Sie daran denken, Eingaben für verschiedene Dateideskriptoren bereitzustellen, ist dies sofort sinnvoll.

Es besteht auch die Möglichkeit, das catkomplett fallen zu lassen . Warum nicht das Here-Dokument direkt zur Verfügung stellen für cmd:

cmd << EOF
input
here
EOF
Jens
quelle
`` `cat << EOF1 << EOF2 first here-doc EOF1 second here-doc EOF2` `` Das oben genannte funktioniert nicht.
user1424739
@ user1424739 Es funktioniert in aktuellen zsh und bash. Die Asche und ksh93 scheinen hier nur das zweite Dokument auszugeben.
Jens
Warum das Downvote? Wenn etwas nicht stimmt, geben Sie mir bitte Gelegenheit, Abhilfe zu schaffen.
Jens
Dies ist ziemlich süß bei der Verwendung sudo tee /etc/securefile.conf <<EOF.
Dragon788
Auf welcher Bash-Version funktioniert es? Mit Bash 4.4.19 (unter Ubuntu 18.04.02) und Bash 5.0 (Docker-Image) habe ich nur das zweite Here-Doc erhalten. Oder gibt es vielleicht eine bestimmte Option?
Huelbois
17

Hmm, ich nehme an, ja, laut dem Test in Bash im POSIX-Modus:

$ bash --posix
$ cat <<EOF |
> ahoj
> nazdar
> EOF
> sed 's/a/b/'
bhoj
nbzdar
TMS
quelle
Nur noch ein kleiner Hinweis: Setzen Sie nach dem Schließen keine Leerzeichen EOF. Die Eingabeaufforderung wird sich seltsam verhalten und Sie werden sich fragen, was zum Teufel los ist
Sridhar Sarnobat
2
Wenn Sie bash im POSIX-Modus ausführen, werden einige Erweiterungen deaktiviert , aber keineswegs sogar fast alle. Obwohl diese Antwort in Bezug auf das, was POSIX zulässt, richtig ist, unterstützt ihre Argumentation dies nicht sehr effektiv.
Charles Duffy
3

Hallo, überprüfe das zum Beispiel

#!/bin/sh
( base32 -d | base64 -d )<<ENDOFTEXT
KNDWW42DNNSHS5ZXPJCG4MSVM5MVQVT2JFCTK3DELBFDCY2IIJYGE2JUJNHWS22LINVHQMCMNVFD
CWJQIIZVUV2JOVNEOVJLINTW6PIK
ENDOFTEXT

Grüße

buc
quelle