Quando você executa este comando:
ls
o terminal exibe a saída de ls.
Quando você executa este comando:
echo $(ls)
o shell captura a saída $(ls)e executa a divisão de palavras nele. Com o padrão IFS, isso significa que todas as seqüências de espaço em branco, incluindo caracteres de nova linha, são substituídas por um único espaço em branco. É por isso que a saída de echo $(ls)aparece em uma linha.
Para uma discussão avançada sobre divisão de palavras, consulte as Perguntas frequentes de Greg .
Suprimindo a divisão de palavras
O shell não executa a divisão de palavras em cadeias entre aspas. Assim, você pode suprimir a divisão de palavras e reter a saída multilinha com:
echo "$(ls)"
ls e saída multilinha
Você deve ter notado que, lsàs vezes, imprime mais de um arquivo por linha:
$ ls
file1 file2 file3 file4 file5 file6
Esse é o padrão quando a saída de lsvai para um terminal. Quando a saída não vai diretamente para um terminal, lsaltera seu padrão para um arquivo por linha:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Esse comportamento está documentado man ls.
Outra sutileza: substituição de comando e novas linhas à direita
$(...)é substituição de comando e o shell remove os caracteres de nova linha à direita da saída da substituição de comando . Isso normalmente não é perceptível porque, por padrão, echoadiciona uma nova linha ao final de sua saída. Portanto, se você perder uma nova linha no final $(...)e a ganhar echo, não haverá alterações. Se, no entanto, a saída do seu comando terminar com 2 ou mais caracteres de nova linha enquanto echoadicionar apenas um, sua saída estará faltando uma ou mais novas linhas. Como exemplo, podemos usar printfpara gerar caracteres de nova linha à direita. Observe que os dois comandos a seguir, apesar do número diferente de novas linhas, produzem a mesma saída de uma linha em branco:
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
Esse comportamento está documentado man bash.
Outra surpresa: expansão do nome do caminho, duas vezes
Vamos criar três arquivos:
$ touch 'file?' file1 file2
Observe a diferença entre ls file?e echo $(ls file?):
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
No caso de echo $(ls file?), o arquivo glob file?é expandido duas vezes , fazendo com que os nomes dos arquivos file1e file2apareçam duas vezes na saída. Isso ocorre porque, como Jeffiekins aponta, a expansão do nome do caminho é realizada primeiro pelo shell antes de lsser executada e depois novamente antes da echoexecução.
A segunda expansão do nome do caminho pode ser suprimida se usamos aspas duplas:
$ echo "$(ls file?)"
file?
file1
file2