Dov'è finito il carattere finale di nuova riga dalla mia sostituzione di comando?


15

Il codice seguente descrive al meglio la situazione. Perché l'ultima riga non sta emettendo il carattere finale newline finale? L'output di ogni riga è mostrato nel commento. Sto usando GNU bash, versione 4.1.5

     echo -n $'a\nb\n'                  | xxd -p  # 610a620a  
           x=$'a\nb\n'   ; echo -n "$x" | xxd -p  # 610a620a
     echo -ne "a\nb\n"                  | xxd -p  # 610a620a
x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p  # 610a62

4
Soluzione alternativa per le rare occasioni in cui è necessario:tmp=$(somecommand; echo a); tmp=${tmp%a}
SO di Gilles


1
@Gilles: Per quanto riguarda il tuo esempio, sopra: tmp=$(somecommand; echo a)... Questo ha sicuramente portato il punto a casa ... Fino a quando non ho visto l'esempio, la mia tendenza sarebbe stata ancora quella di usare echo -n a... ma, ovviamente !, non c'è bisogno di il -n, perché Command Substitution rimuoverà in ogni caso la newline finale introdotta! ... grazie ...
Peter

Risposte:


18

La funzione di sostituzione dei comandi $() (e suo cugino il backtick) rimuove specificamente le nuove righe finali. Questo è il comportamento documentato e dovresti sempre esserne consapevole quando usi il costrutto.

Le nuove righe all'interno del corpo del testo non vengono rimosse dall'operatore di sostituzione, ma possono anche essere rimosse quando si esegue la divisione delle parole sulla shell, quindi il modo in cui ciò risulta dipende dal fatto che tu abbia usato le virgolette o meno. Nota la differenza tra questi due usi:

$ echo -n "$(echo -n 'a\nb')"
a
b

$ !! | xxd -p
610a62

$ echo -n  $(echo -n 'a\nb')
a b

$ !! | xxd -p   
612062

Nel secondo esempio, l'output non è stato citato e la nuova riga è stata interpretata come una divisione di parole, facendola apparire nell'output come uno spazio!


1
Grazie Caleb .. Ero consapevole di dividere le parole cambiando spazio bianco in un singolo spazio quando non quotato ... Ecco perché sono stato molto sorpreso di vedere la mia nuova riga finale scomparire anche se l'avevo citata ... Ora sono consapevole che è a causa del comportamento 'normale' della Sostituzione Comando che lascia cadere una nuova riga finale ... Oh beh, c'est la vie .. e grazie per il link
Peter.O

6

Quando si usa la sostituzione dei comandi, la shell esegue i comandi in una subshell, restituendo il loro stdout. in questo processo, i caratteri IFS perdono il loro significato (se non sono citati), poiché il encomio restituisce semplici parole divise, quindi quelli finali vengono rimossi. Per esempio:

$ echo "$(echo -e '\n')" | wc
 1       0       1

$ echo -e '\n' | wc
2       0       2

e più praticamente, pwdfunzionerà anche se il nome della tua directory ha una nuova riga in mezzo, ma $(pwd)non lo farà.

La solita soluzione alternativa è aggiungere qualcosa alla fine del comando e rimuoverlo in seguito.


1
Grazie Philomath ... a proposito, il tuo primo esempio è sintatticamente sbagliato ('wc' non accetta una stringa come arg). Per te esempi per avere un senso, il primo potrebbe essere echo "$(echo -e '\n')" | wc, quali output 1   0   1, rispetto al2   0   2
Peter

@fred: Oops, solo un errore di battitura.
Philomath,

1
"convertito in spazi" non è la spiegazione appropriata, c'è solo una suddivisione in questione. In particolare è possibile rimuovere lo spazio da IFS e questi non fungeranno da separatori. Inoltre, il tuo esempio rientra in una categoria di casi speciali e c'è una differenza tra $(pwd)e "$(pwd)", vedi la risposta di Caleb.
Stéphane Gimenez,

PS ... Il tuo suggerimento per la solita soluzione alternativa è proprio quello di cui avevo bisogno per chiarire questo.
Peter

Ri "convertiti in spazi", vedi Word Splitting
Peter.O
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.