Sintaxe multilinha para canalizar um heredoc; isso é portátil?

132

Eu estou familiarizado com esta sintaxe:

cmd1 << EOF | cmd2
text
EOF

mas acabei de descobrir que o bash me permite escrever:

cmd1 << EOF |
text
EOF
cmd2

(o heredoc é usado como entrada para cmd1 e a saída de cmd1 é canalizada para cmd2). Parece uma sintaxe muito estranha. É portátil?

William Pursell
fonte
Eu vim aqui para encontrar uma boa maneira de dividir isso em várias linhas: big-long-command1 with lots of args << EOF | big-long-command2 with lots of args. A "sintaxe ímpar" parece ser a melhor maneira.
precisa
Um caso de uso conveniente para isso é quando você está tentando converter uma tabela delimitada por espaço em uma delimitada por tabulação para poder colá-la nas planilhas do Google. Você não precisará criar um arquivo temporário.
Sridhar Sarnobat
O primeiro não funcionou para mim no z-shell. Eu não gosto do segundo porque aliena o | do comando, perdendo a idiomicina (?) dos pipelines de shell.
Sridhar Sarnobat

Respostas:

104

Sim, o padrão POSIX permite isso. De acordo com a versão de 2008:

O documento aqui deve ser tratado como uma única palavra que começa após a próxima <newline>e continua até que exista uma linha contendo apenas o delimitador e a <newline>, sem <blank>caracteres no meio. Então, o próximo documento aqui começa, se houver um.

E inclui este exemplo de vários "documentos aqui" na mesma linha:

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

Portanto, não há nenhum problema ao fazer redirecionamentos ou pipes. Seu exemplo é semelhante a algo assim:

cat file |
cmd

E a gramática do shell (mais abaixo na página vinculada) inclui estas definições:

pipe_sequence    :                             command
                 | pipe_sequence '|' linebreak command

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

Portanto, um símbolo de tubulação pode ser seguido por um final de linha e ainda ser considerado parte de uma tubulação.

Ned Deily
fonte
26

Sim, está na gramática do shell POSIX. Você também pode ter mais de um documento aqui para o mesmo comando (alguns outros exemplos usam duas catinvocações, mas isso também funciona):

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

Isso é artificial (usando 2 documentos aqui para stdin), mas se você pensa em fornecer informações para diferentes descritores de arquivo, isso imediatamente faz sentido.

Há também a possibilidade de abandonar catcompletamente . Por que não disponibilizar o documento aqui diretamente para cmd:

cmd << EOF
input
here
EOF
Jens
fonte
`` `cat << EOF1 << EOF2 primeiro aqui-doc EOF1 segundo aqui-doc EOF2` `` O acima não funciona.
user1424739
@ user1424739 Funciona no zsh e no bash atuais. O ash e ksh93 parecem produzir apenas o segundo documento aqui.
Jens
Por que o voto negativo? Se houver algo impreciso, me dê a oportunidade de remediar.
Jens
Isso é muito fofo ao usar sudo tee /etc/securefile.conf <<EOF.
dragon788
Em que versão do bash funciona? Usando o bash 4.4.19 (no ubuntu 18.04.02) e o bash 5.0 (imagem do docker), obtive apenas o segundo documento aqui. Ou talvez haja uma opção específica?
Huelbois 5/07
17

Hmm, suponho que sim, de acordo com o teste no bash no modo POSIX:

$ bash --posix
$ cat <<EOF |
> ahoj
> nazdar
> EOF
> sed 's/a/b/'
bhoj
nbzdar
TMS
fonte
Apenas mais uma pequena nota: não coloque espaços após o fechamento EOF. O prompt irá se comportar estranhamente e você vai saber o que diabos está errado
Sridhar Sarnobat
2
A execução do bash no modo POSIX desativa algumas extensões, mas de forma alguma quase todas elas. Sendo assim, embora essa resposta esteja correta em termos do que o POSIX permite, seu raciocínio não suporta isso de maneira muito eficaz.
Charles Duffy
3

Olá, verifique isso, por exemplo

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

Saudações

buc
fonte