Składnia wielowierszowa do potokowania heredoc; czy to jest przenośne?

137

Jestem zaznajomiony z tą składnią:

cmd1 << EOF | cmd2
text
EOF

ale właśnie odkryłem, że bash pozwala mi pisać:

cmd1 << EOF |
text
EOF
cmd2

(heredoc jest używany jako dane wejściowe do cmd1, a wyjście cmd1 jest przesyłane potokiem do cmd2). Wydaje się, że jest to bardzo dziwna składnia. Czy jest przenośny?

William Pursell
źródło
Przyszedłem tutaj, aby znaleźć dobrego sposobu podziału tego na wielu liniach: big-long-command1 with lots of args << EOF | big-long-command2 with lots of args. „Dziwna składnia” wydaje się najlepszym sposobem.
PaulC
Jednym z wygodnych przypadków użycia jest sytuacja, gdy próbujesz przekonwertować tabelę rozdzieloną spacjami na tabelę rozdzielaną tabulatorami, aby można ją było wkleić do Arkuszy kalkulacyjnych Google. Nie będziesz musiał tworzyć pliku tymczasowego.
Sridhar Sarnobat,
Pierwszy nie działał dla mnie w powłoce z. Nie podoba mi się ten drugi, ponieważ zraża | z polecenia, tracąc idiomację (?) rurociągów powłokowych.
Sridhar Sarnobat

Odpowiedzi:

109

Tak, standard POSIX na to pozwala. Według wersji z 2008 roku:

Dokument tutaj będzie traktowany jako pojedyncze słowo, które zaczyna się po następnym <newline>i trwa do momentu, gdy pojawi się wiersz zawierający tylko separator i a <newline>, bez <blank>znaków między nimi. Następnie rozpoczyna się następny dokument tutaj, jeśli taki istnieje.

I zawiera ten przykład wielu „dokumentów tutaj” w jednym wierszu:

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

Nie ma więc problemu z przekierowaniami lub potokami. Twój przykład jest podobny do tego:

cat file |
cmd

A gramatyka powłoki (dalej na połączonej stronie) zawiera następujące definicje:

pipe_sequence    :                             command
                 | pipe_sequence '|' linebreak command

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

Tak więc po symbolu rury może następować koniec linii i nadal może być uważany za część rurociągu.

Ned Deily
źródło
26

Tak, jest w gramatyce powłoki POSIX. Możesz także mieć więcej niż jeden dokument here-doc dla tego samego polecenia (niektóre inne przykłady używają dwóch catwywołań, ale to również działa):

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

Jest to wymyślone (używając 2 here-docs dla stdin), ale jeśli myślisz o wprowadzeniu danych wejściowych dla różnych deskryptorów plików, od razu ma to sens.

Istnieje również możliwość całkowitego usunięciacat . Dlaczego nie udostępnić tego dokumentu bezpośrednio dla cmd:

cmd << EOF
input
here
EOF
Jens
źródło
`` `` cat << EOF1 << EOF2 pierwszy tutaj-doc EOF1 drugi tutaj-doc EOF2 '' `` Powyższe nie działa.
user1424739
@ user1424739 Działa w aktualnym zsh i bash. Ash i ksh93 wydają się wyświetlać tylko drugi dokument.
Jens
Dlaczego głos przeciw? Jeśli jest coś niedokładnego, daj mi szansę, aby to naprawić.
Jens
To jest całkiem słodkie podczas używania sudo tee /etc/securefile.conf <<EOF.
dragon788
Na jakiej wersji bash to działa? Używając basha 4.4.19 (na ubuntu 18.04.02) i bash 5.0 (obraz dockera), dostałem tylko drugi tutaj-doc. A może jest jakaś konkretna opcja?
huelbois
18

Hmm, chyba tak, zgodnie z testem w bash w trybie POSIX:

$ bash --posix
$ cat <<EOF |
> ahoj
> nazdar
> EOF
> sed 's/a/b/'
bhoj
nbzdar
TMS
źródło
Jeszcze jedna drobna uwaga: nie umieszczaj spacji po zamknięciu EOF. Monit zachowa się dziwnie i będziesz się zastanawiać, co do cholery jest nie tak
Sridhar Sarnobat
2
Uruchomienie basha w trybie POSIX wyłącza niektóre rozszerzenia, ale w żadnym wypadku nawet prawie wszystkie z nich. W związku z tym, chociaż ta odpowiedź jest poprawna pod względem tego, na co pozwala POSIX, jej rozumowanie nie wspiera tego zbyt skutecznie.
Charles Duffy,
3

Cześć, sprawdź to na przykład

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

pozdrowienia

buc
źródło