Lorsque vous exécutez cette commande:
ls
le terminal affiche la sortie de ls.
Lorsque vous exécutez cette commande:
echo $(ls)
le shell capture la sortie de $(ls)et effectue la division des mots dessus. Avec la valeur par défaut IFS, cela signifie que toutes les séquences d'espaces blancs, y compris les caractères de nouvelle ligne, sont remplacées par un seul blanc. C'est pourquoi la sortie de echo $(ls)apparaît sur une seule ligne.
Pour une discussion avancée sur le fractionnement de mots, consultez la FAQ de Greg .
Suppression de la division des mots
Le shell n'effectue pas de fractionnement de mots sur les chaînes entre guillemets. Ainsi, vous pouvez supprimer le fractionnement de mots et conserver la sortie multiligne avec:
echo "$(ls)"
ls et sortie multiligne
Vous avez peut-être remarqué que lsparfois imprime plus d'un fichier par ligne:
$ ls
file1 file2 file3 file4 file5 file6
Il s'agit de la valeur par défaut lorsque la sortie de lsva à un terminal. Lorsque la sortie ne va pas directement à un terminal, lschange sa valeur par défaut en un fichier par ligne:
$ echo "$(ls)"
file1
file2
file3
file4
file5
file6
Ce comportement est documenté dans man ls.
Autre subtilité: la substitution de commandes et les sauts de ligne
$(...)est la substitution de commande et le shell supprime les caractères de fin de ligne de sortie de la substitution de commande . Cela n'est normalement pas perceptible car, par défaut, echoajoute une nouvelle ligne à la fin de sa sortie. Donc, si vous perdez une nouvelle ligne à la fin de $(...)et que vous en gagnez une echo, il n'y a pas de changement. Si, cependant, la sortie de votre commande se termine par 2 ou plusieurs caractères de echoretour à la ligne alors qu’elle n’en ajoute qu’un, il vous manquera un ou plusieurs retours à la ligne. Par exemple, nous pouvons utiliser printfpour générer des caractères de nouvelle ligne de fin. Notez que les deux commandes suivantes, malgré le nombre différent de sauts de ligne, produisent la même sortie d'une ligne vierge:
$ echo "$(printf "\n")"
$ echo "$(printf "\n\n\n\n\n")"
$
Ce comportement est documenté dans man bash.
Autre surprise: extension du nom de chemin, deux fois
Créons trois fichiers:
$ touch 'file?' file1 file2
Observez la différence entre ls file?et echo $(ls file?):
$ ls file?
file? file1 file2
$ echo $(ls file?)
file? file1 file2 file1 file2
Dans le cas de echo $(ls file?), le glob de fichier file?est développé deux fois , provoquant les noms de fichier file1et file2apparaissant deux fois dans la sortie. En effet, comme le souligne Jeffiekins, l' expansion du nom de chemin est effectuée d'abord par le shell avant l' lsexécution, puis à nouveau avant l' echoexécution.
La deuxième extension de chemin peut être supprimée si nous utilisons des guillemets doubles:
$ echo "$(ls file?)"
file?
file1
file2