Die Ausgabe von ls enthält Zeilenumbrüche, wird jedoch in einer einzelnen Zeile angezeigt. Warum?

41

Ich denke, ich kann einen relativ grundlegenden Punkt in Bezug auf Shell übersehen. Die Ausgabe des Befehls ls trennt die Ausgabe standardmäßig durch Zeilenumbrüche, die Shell zeigt die Ausgabe jedoch in einer einzelnen Zeile an.

Kann mir das jemand erklären? Ich hatte immer angenommen, dass die Ausgabe einfach durch Leerzeichen getrennt ist, aber jetzt, da ich die Ausgabe durch Zeilenumbrüche getrennt sehe, würde ich erwarten, dass die Ausgabe in separaten Zeilen angezeigt wird.

Beispiel:

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

od zeigt an, dass die Ausgabe durch Zeilenumbrüche getrennt ist:

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

Wenn Zeilenumbrüche vorhanden sind, wird die Ausgabe dann nicht wie folgt angezeigt:

text1 
text2
text3
zod90
quelle

Antworten:

44

Wenn Sie die Ausgabe leiten, lsverhält es sich anders.

Diese Tatsache ist in der Infodokumentation verborgen :

Wenn die Standardausgabe ein Terminal ist, erfolgt die Ausgabe in Spalten (vertikal sortiert) und Steuerzeichen werden als Fragezeichen ausgegeben. Andernfalls wird die Ausgabe zeilenweise aufgelistet und die Steuerzeichen werden unverändert ausgegeben.

Versuchen Sie es mit dem Laufen, um es zu beweisen

ls

und dann

ls | less

Das heißt, wenn Sie möchten, dass die Ausgabe garantiert eine Datei pro Zeile ist, unabhängig davon, ob sie weitergeleitet oder umgeleitet wird, müssen Sie sie ausführen

ls -1

( -1ist die Nummer eins)

Sie können auch ls | lessdie Ausgabe in Spalten erzwingen , indem Sie ausführen

ls -C

( -Cist ein Großbuchstabe C)

Mikel
quelle
6
@theconnorpower: es ist ziemlich spezifisch für ls. Es ist nützlich, aber eindeutig inkonsistent und überraschend. Beachten Sie jedoch, dass einige Befehle, die eine farbige Ausgabe erzeugen, die Farben auch bei der Pipe-Verarbeitung entfernen.
Mikel
5
@theconnorpower: Wissenswertes: Die Erfinder von Unix schrieben weiter Plan9. In Plan9 wird lsimmer eine pro Zeile und lcimmer in Spalten gedruckt.
Mikel
2
@theconnorpower: Es gibt auch Programme, die die Größe des Terminals lesen und ihre Ausgabe entsprechend anpassen, zum Beispiel wird unter Debian dpkg -ldie gesamte Breite des Bildschirms verwendet, aber wenn es in einer Pipe gedruckt wird, wird davon ausgegangen, dass das Terminal 80 Spalten breit ist , und kürzt die Ausgabe ab, um sie bei Bedarf anzupassen.
Mikel
1
@Mikel Interessant, die Unterschiede zwischen ls und lc in Plan9 zu hören. Danke für die ausführliche Antwort.
zod90
1
Wie kann ein Programm feststellen, ob seine Ausgabe in eine Datei umgeleitet wird oder ob es in eine Shell geht?
user2820379
4

Ihre Entdeckung zeigt den Hauptgrund auf, warum das Parsen der Ausgabe lsimmer eine schlechte Idee ist. Eine vollständige Erklärung finden Sie in Gregs Wiki .

Denken Sie umgekehrt an Ihr Problem. Sie haben bemerkt, dass ls manchmal Zeilenumbrüche zwischen den Ausgaben druckt und manchmal nicht. Für die Verwendung in Skripten oder wenn es durch das -1Flag erzwungen wird . Eine neue Zeile am Ende jeder Datei. Was gibt es keine Garantie, dass jede Zeile einen neuen Dateinamen darstellt . Wenn ein Dateiname eine neue Zeile enthält, kann die Ausgabe von ls nicht analysiert werden. Betrachten Sie diese Dateinamen:

file1
file2\nfile3
file4

Wenn Sie ls -1ein Verzeichnis mit dem darin haben, würden Sie etwas bekommen, das so aussieht:

file1
file2
file3
file4

Würden Sie nicht natürlich davon ausgehen, dass es vier Dateien gibt? Dies gilt auch für Skripte, die die Ausgabe von ls analysieren. In Wirklichkeit gibt es drei Dateien, eine davon mit einem kniffligen Namen, aber Sie könnten das nicht aus der Ausgabe von ls herausfinden. *

* Es sei denn, Sie haben das -lFlag verwendet und festgestellt, dass die Ausgabe nicht mehr funktioniert, Ihre Skripte jedoch immer noch blockiert sind.

Caleb
quelle
3
Wenn Sie die Ausgabe von wirklich analysieren müssen ls, kann die -bOption helfen. Es macht die Newline in \nusw.
Mikel