Em esta pergunta alguém relata um problema usando um documento aqui com uma palavra delimitador citado dentro $(...)
substituição de comando , onde uma barra invertida \
no final de uma linha dentro do gatilhos de documentos -juntando nova linha de continuação de linha , enquanto o mesmo aqui documentar fora obras de substituição de comando como esperado .
Aqui está um exemplo de documento simplificado:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Isso inclui um backtick e uma barra invertida no final de uma linha. O delimitador é citado, portanto, nenhuma expansão ocorre dentro do corpo. Em todos os Bourne-alikes, posso encontrar isso com o conteúdo literalmente. Se eu colocar o mesmo documento dentro de uma substituição de comando da seguinte maneira:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
então eles não se comportam mais de forma idêntica:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
e SunOS 5,10 POSIXsh
todos dão os conteúdos textuais do documento, como antes.- O Bash 3.2 fornece um erro de sintaxe para um backtick incomparável. Com backticks correspondentes, ele tenta executar o conteúdo como um comando.
- O Bash 4.3 recolhe "ghi" e "jkl" em uma única linha, mas não apresenta erro. A
--posix
opção não afeta isso. Kusalananda me diz (obrigado!) Quepdksh
se comporta da mesma maneira .
Na pergunta original, eu disse que isso era um bug no analisador de Bash. É isso? [Update: yes ] O texto relevante do POSIX (todos da definição da Linguagem de Comando do Shell) que posso encontrar é:
- §2.6.3 Substituição de comando :
Com o formulário $ (comando), todos os caracteres que seguem o parêntese aberto ao parêntese de fechamento correspondente constituem o comando. Qualquer script de shell válido pode ser usado para comando , exceto um script que consiste apenas em redirecionamentos que produz resultados não especificados.
- §2.7.4 Aqui-Documento :
Se qualquer parte da palavra for citada, o delimitador será formado pela remoção da cotação na palavra , e as linhas do documento aqui não serão expandidas.
- §2.2.1 Caractere de escape (barra invertida) :
Se uma <linha nova> segue a <barra invertida>, o shell deve interpretar isso como continuação de linha. A barra invertida e a linha nova devem ser removidas antes de dividir a entrada em tokens.
- §2.3 Reconhecimento de token :
Quando um token io_here for reconhecido pela gramática (consulte Shell Grammar ), uma ou mais das linhas subseqüentes imediatamente após o próximo token NEWLINE formarão o corpo de um ou mais documentos aqui e serão analisadas de acordo com as regras do Here- Documento .
Quando não está processando um io_here , o shell deve dividir sua entrada em tokens aplicando a primeira regra aplicável abaixo ao próximo caractere em sua entrada. ...
...
- Se o caractere atual for <barra invertida>, aspas simples ou aspas duplas e não estiver entre aspas, ele afetará as aspas para os caracteres subseqüentes até o final do texto entre aspas. As regras para cotação são as descritas em Cotação . Durante o reconhecimento do token, nenhuma substituição deve ser realmente executada, e o token resultante deve conter exatamente os caracteres que aparecem na entrada (exceto para <newline> junção), sem modificação, incluindo cotações incorporadas ou anexas ou operadores de substituição, entre o e o final do texto citado.
Minha interpretação disso é que todos os caracteres depois $(
até o final )
compreendem o script do shell, literalmente; um documento aqui aparece, então o processamento do documento aqui ocorre em vez da tokenização comum; o documento aqui possui um delimitador entre aspas, o que significa que seu conteúdo é processado literalmente; e o personagem de escape nunca entra nele. Eu posso ver um argumento, no entanto, de que este caso simplesmente não é abordado, e ambos os comportamentos são permitidos. É possível que eu tenha pulado algum texto relevante em algum lugar também.
- Essa situação ficou mais clara em outro lugar?
- Em que um script portátil pode confiar (em teoria)?
- O tratamento específico dado por qualquer uma dessas conchas (Bash 3.2 / Bash 4.3 / todos os outros) é exigido pelo padrão? Proibido? Permitido?
echo "$x"
, mas qualquer maneira de inspecionar a variável funciona. Eu editei essa linha na parte inferior.
$(...)
por qualquer que seja a saída ... Agora, ao executar o comando no seu exemplo em um subshell (in bash
), ele gera o resultado esperado. É somente ao transformá-lo em substituição de comando que ele recolhe "ghi" e "jkl". Portanto, este é um erro imo