La sortie de ls a des nouvelles lignes mais s'affiche sur une seule ligne. Pourquoi?

41

Je pense que je peux négliger un point relativement fondamental concernant la coquille. La sortie de la commande ls par défaut sépare la sortie avec des nouvelles lignes, mais le shell affiche la sortie sur une seule ligne.

Quelqu'un peut-il m'expliquer cela? J'avais toujours supposé que la sortie était simplement séparée par des espaces, mais maintenant que je vois la sortie séparée par des nouvelles lignes, je m'attendrais à ce que la sortie s'affiche sur des lignes séparées.

Exemple:

cpoweradm@debian:~/lpi103-4$ ls text*
text1  text2  text3

od montre que la sortie est séparée par des nouvelles lignes:

cpoweradm@debian:~/lpi103-4$ ls text* | od -c
0000000   t   e   x   t   1  \n   t   e   x   t   2  \n   t   e   x   t
0000020   3  \n
0000022

Si les nouvelles lignes sont présentes, alors pourquoi la sortie ne s'affiche-t-elle pas sous la forme:

text1 
text2
text3
zod90
la source

Réponses:

44

Lorsque vous dirigez la sortie, lsagit différemment.

Ce fait est caché dans la documentation info :

Si la sortie standard est un terminal, la sortie est en colonnes (triées verticalement) et les caractères de contrôle sont générés en tant que points d'interrogation. sinon, la sortie est répertoriée une par ligne et les caractères de contrôle sont générés tels quels.

Pour le prouver, essayez de courir

ls

et alors

ls | less

Cela signifie que si vous voulez que la sortie soit garantie à un fichier par ligne, qu'elle soit redirigée ou redirigée, vous devez exécuter

ls -1

( -1est le numéro un)

Ou, vous pouvez forcer la ls | lesssortie en colonnes en exécutant

ls -C

( -Cest un C majuscule)

Mikel
la source
6
@theconnorpower: c'est à peu près spécifique à ls. C'est utile, mais clairement incohérent et surprenant. Notez cependant que certaines commandes produisant une sortie colorée effacent également les couleurs lorsqu'elles sont redirigées.
Mikel
5
@theconnorpower: Jeu-questionnaire: Les inventeurs d'Unix ont ensuite écrit Plan9. Dans Plan9, lsen imprime toujours un par ligne et lctoujours en colonnes.
Mikel
2
@theconnorpower: Il existe également des programmes qui lisent la taille du terminal et ajustent leur sortie en conséquence, par exemple, Debian dpkg -lutilisera toute la largeur de l'écran, mais si vous imprimez sur un tuyau, le terminal suppose une largeur de 80 colonnes. , et abrége la sortie pour l’adapter si nécessaire.
Mikel
1
@ Mikel Intéressant d'entendre les différences entre LS et LC dans Plan9. Merci pour la réponse détaillée.
Zod90
1
Comment un programme peut-il déterminer si sa sortie est redirigée vers un fichier ou si elle va dans un shell?
user2820379
4

Votre découverte met en évidence la raison principale pour laquelle analyser la sortie de lsest toujours une mauvaise idée. Voir le wiki de Greg pour une explication complète .

Pensez à votre problème en sens inverse. Vous avez remarqué que ls imprime et parfois n'imprime pas de nouvelles lignes entre ses sorties. Pour une utilisation dans des scripts ou lorsque forcé par le -1drapeau, c'est le cas. Une nouvelle ligne à la fin de chaque fichier. Rien ne garantit que chaque nouvelle ligne représente un nouveau nom de fichier . En fait, si un nom de fichier contient une nouvelle ligne elle-même, la sortie de ls sera absolument impossible à analyser. Considérez ces noms de fichiers:

file1
file2\nfile3
file4

Lorsque vous avez ls -1un répertoire contenant cela, vous obtenez quelque chose qui ressemble à ceci:

file1
file2
file3
file4

Ne penseriez-vous pas naturellement qu'il y avait quatre fichiers? Il en serait de même des scripts qui analysent la sortie de ls. En réalité, il y a trois fichiers, l'un avec un nom compliqué, mais vous ne pourriez pas le savoir à partir de la sortie de ls. *

* À moins que vous n'utilisiez le -ldrapeau et que vous remarquiez que la sortie était bouchée, mais vos scripts resteraient quand même étouffés.

Caleb
la source
3
Si vous devez vraiment analyser le résultat de ls, l' -boption peut vous aider. Il transforme la nouvelle ligne en \n, etc.
Mikel