Quando si esegue questo comando:
ls
il terminale visualizza l'uscita di ls.
Quando si esegue questo comando:
echo $(ls)
la shell cattura l'output di $(ls)ed esegue la divisione delle parole su di esso. Con l'impostazione predefinita IFS, ciò significa che tutte le sequenze di spazi bianchi, inclusi i caratteri di nuova riga, vengono sostituite da un singolo spazio vuoto. Ecco perché l'output di echo $(ls)appare su una riga.
Per una discussione avanzata sulla suddivisione delle parole, vedere le FAQ di Greg .
Sopprimendo la divisione delle parole
La shell non esegue la divisione delle parole tra stringhe tra virgolette. Pertanto, è possibile eliminare la suddivisione delle parole e conservare l'output multilinea con:
echo "$(ls)"
ls e output multilinea
Potresti aver notato che a lsvolte stampa più di un file per riga:
$ ls
file1 file2 file3 file4 file5 file6
Questo è il valore predefinito quando l'output di lsva a un terminale. Quando l'output non sta andando direttamente a un terminale, lscambia il suo valore predefinito in un file per riga:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Questo comportamento è documentato in man ls.
Un'altra sottigliezza: sostituzione dei comandi e nuove righe finali
$(...)è la sostituzione dei comandi e la shell rimuove i caratteri di nuova riga finali dall'output della sostituzione dei comandi . Questo normalmente non è evidente perché, per impostazione predefinita, echoaggiunge una nuova riga alla fine del suo output. Quindi, se perdi una nuova linea dalla fine di $(...)e ne guadagni una echo, non ci sono cambiamenti. Se, tuttavia, l'output del comando termina con 2 o più caratteri di nuova riga mentre ne echoaggiunge solo uno, nell'output mancheranno una o più nuove righe. Ad esempio, possiamo usare printfper generare caratteri di nuova riga finali. Si noti che entrambi i seguenti comandi, nonostante il diverso numero di nuove righe, producono lo stesso output di una riga vuota:
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
Questo comportamento è documentato in man bash.
Un'altra sorpresa: l'espansione del nome percorso, due volte
Creiamo tre file:
$ touch 'file?' file1 file2
Osserva la differenza tra ls file?e echo $(ls file?):
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
Nel caso di echo $(ls file?), il file glob file?viene espanso due volte , causando i nomi dei file file1e file2apparire due volte nell'output. Questo perché, come sottolinea Jeffiekins, l' espansione del nome percorso viene eseguita prima dalla shell prima che lsvenga eseguita e poi ancora primaecho venga eseguita.
La seconda espansione del nome percorso può essere soppressa se abbiamo usato le virgolette doppie:
$ echo "$(ls file?)"
file?
file1
file2