Considérez les deux échantillons de coque
$ ls
myDoc.html
SomeDirectory
someDoc.txt
et
$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt
Le premier s'exécute ls
qui, si je comprends bien, ajoute le contenu du répertoire de travail actuel au stdout
fichier (qui est ce que le terminal affiche). Est-ce correct?
Le second prend la valeur de la ls
commande (c'est-à-dire le contenu du répertoire de travail courant) et l'imprime dans le stdout
fichier. Est-ce correct?
Pourquoi les deux commandes donnent-elles des sorties différentes?
ls
soi, il ne vous donne pas plusieurs éléments par ligne?echo *
?Réponses:
Lorsque vous exécutez cette commande:
le terminal affiche la sortie de
ls
.Lorsque vous exécutez cette commande:
le shell capture la sortie de
$(ls)
et effectue la division des mots dessus. Avec la valeur par défautIFS
, 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 deecho $(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:
ls
et sortie multiligneVous avez peut-être remarqué que
ls
parfois imprime plus d'un fichier par ligne:Il s'agit de la valeur par défaut lorsque la sortie de
ls
va à un terminal. Lorsque la sortie ne va pas directement à un terminal,ls
change sa valeur par défaut en un fichier par ligne: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,echo
ajoute une nouvelle ligne à la fin de sa sortie. Donc, si vous perdez une nouvelle ligne à la fin de$(...)
et que vous en gagnez uneecho
, il n'y a pas de changement. Si, cependant, la sortie de votre commande se termine par 2 ou plusieurs caractères deecho
retour à la ligne alors qu’elle n’en ajoute qu’un, il vous manquera un ou plusieurs retours à la ligne. Par exemple, nous pouvons utiliserprintf
pour 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:Ce comportement est documenté dans
man bash
.Autre surprise: extension du nom de chemin, deux fois
Créons trois fichiers:
Observez la différence entre
ls file?
etecho $(ls file?)
:Dans le cas de
echo $(ls file?)
, le glob de fichierfile?
est développé deux fois , provoquant les noms de fichierfile1
etfile2
apparaissant 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'ls
exécution, puis à nouveau avant l'echo
exécution.La deuxième extension de chemin peut être supprimée si nous utilisons des guillemets doubles:
la source
isatty
vous pouvez vérifier si stdout est un tty, ls l'utilise pour déterminer s'il faut utiliser des couleurs ou non.$( )
fournissez- vous réellement une barrière de syntaxe pour que vous n'ayez pas besoin d'interpoler?$()
fournit une barrière de syntaxe.echo
commande étendra le caractère générique . Par exemple, sils
renvoie un fichier? file1 file2 , puisecho $(ls)
retournera le fichier? fichier1 fichier2 fichier1 fichier2 .echo
ne développe pas les caractères génériques; le shell fait avant de passer l'expansion résultante comme arguments àecho
.ls
sait s'il envoie ou non une sortie à un terminal.L'exécution
ls
à l'invite de commandes écrira sur votre pseudo-tty. Rediriger la sortie dels
ne se fera généralement pas vers un pseudo-tty etls
formatera la sortie différemment.la source