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 ls
volte stampa più di un file per riga:
$ ls
file1 file2 file3 file4 file5 file6
Questo è il valore predefinito quando l'output di ls
va a un terminale. Quando l'output non sta andando direttamente a un terminale, ls
cambia 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, echo
aggiunge 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 echo
aggiunge solo uno, nell'output mancheranno una o più nuove righe. Ad esempio, possiamo usare printf
per 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 file1
e file2
apparire due volte nell'output. Questo perché, come sottolinea Jeffiekins, l' espansione del nome percorso viene eseguita prima dalla shell prima che ls
venga 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