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 de $(ls)
e executa divisão de palavras . Com o padrão IFS
, isso significa que todas as sequências de espaço em branco, incluindo os 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 a divisão de palavras, consulte Perguntas frequentes de Greg .
Suprimir a divisão de palavras
O shell não executa a divisão de palavras em strings entre aspas. Assim, você pode suprimir a divisão de palavras e manter a saída de múltiplas linhas com:
echo "$(ls)"
ls
e saída de múltiplas linhas
Você deve ter notado que ls
às vezes imprime mais de um arquivo por linha:
$ ls
file1 file2 file3 file4 file5 file6
Este é o padrão quando a saída de ls
vai para um terminal. Quando a saída não está indo diretamente para um terminal, ls
altera seu padrão para um arquivo por linha:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Esse comportamento está documentado em man ls
.
Outra sutileza: substituição de comandos e novas linhas finais
$(...)
é substituição de comandos e o shell remove os caracteres de nova linha à direita da saída da substituição de comandos . Isso normalmente não é perceptível porque, por padrão, echo
adiciona uma nova linha ao final de sua saída. Portanto, se você perder uma nova linha no final de $(...)
e obtiver uma de echo
, não haverá alteração. Se, no entanto, a saída do seu comando terminar com 2 ou mais caracteres de nova linha enquanto echo
adicionar novamente apenas um, sua saída não terá uma ou mais novas linhas. Por exemplo, podemos usar printf
para 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 em man bash
.
Outra surpresa: expansão 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 file1
e file2
apareçam duas vezes na saída. Isso porque, como Jeffiekins aponta, a expansão do nome do caminho é executada primeiro pelo shell antes de o ls
ser executado e novamente antes que o echo
seja executado.
A segunda expansão do nome do caminho pode ser suprimida se usarmos aspas duplas:
$ echo "$(ls file?)"
file?
file1
file2