In questa domanda qualcuno segnala un problema usando un documento qui con una parola delimitatore tra virgolette all'interno della $(...)
sostituzione del comando , in cui una barra rovesciata \
alla fine di una riga all'interno del documento innesca la continuazione della linea che unisce la nuova riga , mentre lo stesso documento qui fuori dalla sostituzione del comando funziona come previsto .
Ecco un documento di esempio semplificato:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Ciò include un backtick e un backslash alla fine di una riga. Il delimitatore è citato, quindi non si verificano espansioni all'interno del corpo. In tutti i Bourne-simili posso trovare questo output il contenuto alla lettera. Se inserisco lo stesso documento all'interno di una sostituzione comando come segue:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
quindi non si comportano più in modo identico:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
e SunOS 5.10 POSIXsh
tutti danno il contenuto testuali del documento, come prima.- Bash 3.2 fornisce un errore di sintassi per un backtick senza pari. Con i backtick abbinati, tenta di eseguire il contenuto come comando.
- Bash 4.3 comprime "ghi" e "jkl" su una sola riga, ma non presenta errori. L'
--posix
opzione non influisce su questo. Kusalananda mi dice (grazie!) Chepdksh
si comporta allo stesso modo .
Nella domanda originale, ho detto che si trattava di un bug nel parser di Bash. È? [Aggiornamento: sì ] Il testo pertinente di POSIX (tutto dalla definizione del linguaggio dei comandi Shell) che posso trovare è:
- §2.6.3 Sostituzione comando :
Con il modulo $ (comando), tutti i caratteri che seguono la parentesi aperta alla parentesi di chiusura corrispondente costituiscono il comando. È possibile utilizzare qualsiasi script shell valido per il comando , ad eccezione di uno script costituito esclusivamente da reindirizzamenti che produce risultati non specificati.
- §2.7.4 Here-Document :
Se viene citata una qualsiasi parte della parola , il delimitatore deve essere formato eseguendo la rimozione della citazione sulla parola e le righe del documento qui non devono essere espanse.
- §2.2.1 Carattere di escape (barra rovesciata) :
Se una <newline> segue la <barra rovesciata>, la shell deve interpretarla come continuazione della linea. <slash> e <newline> devono essere rimossi prima di dividere l'input in token.
- §2.3 Riconoscimento token :
Quando un token io_here è stato riconosciuto dalla grammatica (vedi Shell Grammar ), una o più delle righe successive immediatamente successive al token NEWLINE successivo formano il corpo di uno o più documenti qui e devono essere analizzate secondo le regole del Here- Documento .
Quando non sta elaborando un io_here , la shell deve suddividere il proprio input in token applicando la prima regola applicabile di seguito al carattere successivo nel suo input. ...
...
- Se il carattere corrente è <barra rovesciata>, virgoletta singola o virgoletta doppia e non viene citato, influisce sulla quotazione per i caratteri successivi fino alla fine del testo tra virgolette. Le regole per la quotazione sono descritte in Citazioni . Durante il riconoscimento del token non deve essere effettivamente eseguita alcuna sostituzione e il token risultante deve contenere esattamente i caratteri che compaiono nell'input (eccetto per il <newline> join), non modificati, comprese eventuali virgolette o operatori di sostituzione incorporati o che racchiudono, tra la e la fine del testo citato.
La mia interpretazione di questo è che tutti i personaggi che seguono $(
fino al termine )
comprendono lo script della shell, alla lettera; appare un documento qui, quindi l'elaborazione del documento qui avviene invece della tokenizzazione ordinaria; il documento qui ha quindi un delimitatore citato, il che significa che il suo contenuto viene elaborato alla lettera; e il personaggio di fuga non vi entra mai. Riesco a vedere una discussione, tuttavia, che questo caso semplicemente non viene affrontato ed entrambi i comportamenti sono ammessi. È possibile che io abbia saltato qualche testo rilevante anche da qualche parte.
- Questa situazione è resa più chiara altrove?
- Su cosa dovrebbe basarsi uno script portatile (in teoria)?
- Il trattamento specifico fornito da una di queste conchiglie (Bash 3.2 / Bash 4.3 / chiunque altro) è obbligatorio per lo standard? Proibito? Consentito?
echo "$x"
, ma qualsiasi modo di ispezionare la variabile funziona. Ho modificato quella riga in fondo.
$(...)
con qualunque cosa sia l'output ... Ora, quando si esegue il comando nell'esempio in una subshell (in bash
), genera il risultato atteso. È solo quando lo trasforma in sostituzione del comando che collassa "ghi" e "jkl". Quindi questo è un bug imo