Wyjście z ls ma znaki nowej linii, ale wyświetla się w jednym wierszu. Dlaczego?

41

Myślę, że mogę przeoczyć względnie podstawową kwestię dotyczącą powłoki. Dane wyjściowe z polecenia ls domyślnie rozdzielają dane wyjściowe nowymi wierszami, ale powłoka wyświetla dane wyjściowe w jednym wierszu.

Czy ktoś może mi to wytłumaczyć? Zawsze zakładałem, że dane wyjściowe były po prostu oddzielone spacjami, ale teraz, gdy widzę dane wyjściowe oddzielone znakami nowej linii, oczekiwałbym, że dane wyjściowe będą wyświetlane w osobnych wierszach.

Przykład:

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

od pokazuje, że dane wyjściowe są oddzielone znakami nowej linii:

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

Jeśli nowe linie są obecne, to dlaczego dane wyjściowe nie są wyświetlane jako:

text1 
text2
text3
zod90
źródło

Odpowiedzi:

44

Kiedy potokujesz wyjście, lsdziała inaczej.

Ten fakt jest ukryty w dokumentacji informacyjnej :

Jeśli standardowym wyjściem jest terminal, dane wyjściowe są w kolumnach (posortowane pionowo), a znaki sterujące są wyprowadzane jako znaki zapytania; w przeciwnym razie dane wyjściowe są wyświetlane po jednym w wierszu, a znaki sterujące są wyświetlane w niezmienionej postaci.

Aby to udowodnić, spróbuj uruchomić

ls

i wtedy

ls | less

Oznacza to, że jeśli chcesz, aby wynik był gwarantowany jako jeden plik w wierszu, niezależnie od tego, czy jest przesyłany potokowo, czy przekierowywany, musisz uruchomić

ls -1

( -1jest numerem jeden)

Lub możesz wymusić ls | lesswyjście w kolumnach, uruchamiając

ls -C

( -Cjest wielką literą C)

Mikel
źródło
6
@theconnorpower: jest to dość specyficzne ls. Jest użyteczny, ale wyraźnie niespójny i zaskakujący. Pamiętaj jednak, że niektóre polecenia, które generują kolorowe wydruki, usuwają kolory również podczas pipowania.
Mikel
5
@theconnorpower: Trivia: Wynalazcy Uniksa napisali Plan9. W Plan9 lszawsze drukuje po jednym w wierszu i lczawsze drukuje w kolumnach.
Mikel
2
@theconnorpower: Istnieją również programy, które odczytują rozmiar terminala i odpowiednio dostosowują swoje wyjście, na przykład na Debianie dpkg -lwykorzysta całą szerokość ekranu, ale jeśli drukuje na rurze, zakłada, że ​​terminal ma szerokość 80 kolumn , i skraca wyjście, aby dopasować je w razie potrzeby.
Mikel
1
@Mikel Interesujące jest usłyszeć różnice ls / lc w Planie9. Dziękuję za szczegółową odpowiedź.
zod90
1
W jaki sposób program może ustalić, czy dane wyjściowe są przekierowywane do pliku, czy też do powłoki?
user2820379,
4

Twoje odkrycie podkreśla główny powód, dla którego analizowanie wyników lsjest zawsze złym pomysłem. Zobacz wiki Grega, by uzyskać pełne wyjaśnienie .

Pomyśl o swoim problemie na odwrót. Zauważyłeś, że ls czasami robi, a czasami nie drukuje znaków nowej linii między danymi wyjściowymi. Do użytku w skryptach lub po wymuszeniu -1flagi. Jedna nowa linia na końcu każdego pliku. Co nie ma gwarancji, że każda nowa linia reprezentuje nową nazwę pliku . W rzeczywistości, jeśli nazwa pliku zawiera nowy wiersz, wynik działania ls będzie absolutnie niemożliwy do parsowania. Rozważ te nazwy plików:

file1
file2\nfile3
file4

Gdy masz ls -1katalog z tym, dostaniesz coś, co wyglądało tak:

file1
file2
file3
file4

Czy naturalnie nie założyłbyś, że są cztery pliki? Podobnie skrypty analizujące dane wyjściowe ls. W rzeczywistości istnieją trzy pliki, jeden z trudną nazwą, ale nie byłbyś w stanie tego zrozumieć na podstawie danych wyjściowych ls. *

* Chyba że użyjesz -lflagi i zauważysz, że wynik został zablokowany, ale twoje skrypty nadal dławią się.

Caleb
źródło
3
Jeśli naprawdę musisz przeanalizować dane wyjściowe ls, -bopcja może pomóc. Zmienia nową linię w \nitp.
Mikel