Cuando ejecutas este comando:
ls
el terminal muestra la salida de ls.
Cuando ejecutas este comando:
echo $(ls)
el shell captura la salida $(ls)y realiza la división de palabras en él. Con el valor predeterminado IFS, esto significa que todas las secuencias de espacios en blanco, incluidos los caracteres de nueva línea, se reemplazan por un solo espacio en blanco. Es por eso que la salida de echo $(ls)aparece en una línea.
Para una discusión avanzada sobre la división de palabras, vea las preguntas frecuentes de Greg .
Suprimir la división de palabras
El shell no realiza la división de palabras en cadenas entre comillas. Por lo tanto, puede suprimir la división de palabras y retener la salida multilínea con:
echo "$(ls)"
ls y salida multilínea
Es posible que haya notado que a lsveces imprime más de un archivo por línea:
$ ls
file1 file2 file3 file4 file5 file6
Este es el valor predeterminado cuando la salida de lsva a un terminal. Cuando la salida no va directamente a una terminal, lscambia su valor predeterminado a un archivo por línea:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Este comportamiento está documentado en man ls.
Otra sutileza: sustitución de comandos y líneas nuevas
$(...)es la sustitución de comandos y el shell elimina los caracteres de línea nueva del resultado de la sustitución de comandos . Esto normalmente no se nota porque, por defecto, echoagrega una nueva línea al final de su salida. Por lo tanto, si pierde una nueva línea desde el final $(...)y gana una echo, no hay cambio. Sin embargo, si la salida de su comando termina con 2 o más caracteres de nueva línea y echoagrega solo uno, a su salida le faltarán una o más nuevas líneas. Como ejemplo, podemos usar printfpara generar caracteres de nueva línea finales. Tenga en cuenta que los dos comandos siguientes, a pesar del número diferente de líneas nuevas, producen el mismo resultado de una línea en blanco:
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
Este comportamiento está documentado en man bash.
Otra sorpresa: expansión del nombre de ruta, dos veces
Vamos a crear tres archivos:
$ touch 'file?' file1 file2
Observe la diferencia entre ls file?y echo $(ls file?):
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
En el caso de echo $(ls file?)la glob archivo file?se expande en dos ocasiones , haciendo que los nombres de archivo file1y file2de aparecer dos veces en la salida. Esto se debe a que, como señala Jeffiekins, la expansión del nombre de ruta se realiza primero por el shell antes de lsejecutarse y luego nuevamente antes de echoejecutarse.
La segunda expansión del nombre de ruta se puede suprimir si usamos comillas dobles:
$ echo "$(ls file?)"
file?
file1
file2