A saída de ls tem novas linhas, mas é exibida em uma única linha. Por quê?

41

Eu acho que posso estar ignorando um ponto relativamente fundamental em relação ao shell. A saída do comando ls, por padrão, separa a saída com novas linhas, mas o shell exibe a saída em uma única linha.

Alguém pode me explicar isso? Sempre presumi que a saída fosse simplesmente separada por espaços, mas agora que vejo a saída separada por novas linhas, esperaria que a saída fosse exibida em linhas separadas.

Exemplo:

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

od mostra que a saída é separada por novas linhas:

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

Se novas linhas estiverem presentes, por que a saída não é exibida como:

text1 
text2
text3
zod90
fonte

Respostas:

44

Quando você canaliza a saída, lsage de maneira diferente.

Este fato está oculto na documentação info :

Se a saída padrão for um terminal, a saída será em colunas (classificadas verticalmente) e os caracteres de controle serão exibidos como pontos de interrogação; caso contrário, a saída será listada uma por linha e os caracteres de controle serão exibidos como estão.

Para provar isso, tente executar

ls

e depois

ls | less

Isso significa que, se você deseja que a saída seja garantida como um arquivo por linha, independentemente de estar sendo canalizada ou redirecionada, é necessário executar

ls -1

( -1é o número um)

Ou, você pode forçar ls | lessa saída em colunas executando

ls -C

( -Cé um C maiúsculo)

Mikel
fonte
6
@ theconnorpower: é praticamente específico ls. É útil, mas é claramente inconsistente e surpreendente. Mas observe que alguns comandos que produzem saída colorida removerão as cores ao serem canalizados também.
11117 Mikel
5
@theconnorpower: Curiosidades: Os inventores do Unix escreveram o Plano9. No Plano9, lssempre imprime um por linha e lcsempre imprime em colunas.
Mikel
2
@theconnorpower: Também existem programas que leem o tamanho do terminal e ajustam sua saída de acordo, por exemplo, no Debian dpkg -lusará toda a largura da tela, mas se estiver imprimindo em um tubo, assume que o terminal tem 80 colunas de largura e abrevia a saída para ajustá-la, se necessário.
Mikel
1
@ Mikel Interessante ouvir as diferenças ls / lc no Plan9. Obrigado pela resposta detalhada.
Zod90
1
Como um programa pode determinar se sua saída é redirecionada para um arquivo ou se está indo para um shell?
usar o seguinte comando
4

Sua descoberta destaca o principal motivo pelo qual a análise da saída lsé sempre uma má ideia. Veja o wiki de Greg para uma explicação completa .

Pense no seu problema ao contrário. Você notou que ls às vezes imprime e às vezes não imprime novas linhas entre a saída. Para uso em scripts ou quando forçado pelo -1sinalizador, ele faz. Uma nova linha no final de cada arquivo. O que não há garantia de que cada nova linha represente um novo nome de arquivo . De fato, se um nome de arquivo contiver uma nova linha, a saída de ls será absolutamente impossível de analisar. Considere estes nomes de arquivos:

file1
file2\nfile3
file4

Quando você ls -1cria um diretório com isso, obtém algo parecido com isto:

file1
file2
file3
file4

Você naturalmente não pensaria que havia quatro arquivos? Assim como qualquer script que analise a saída de ls. Na realidade, existem três arquivos, um com um nome complicado, mas você não seria capaz de descobrir isso a partir da saída de ls. *

* A menos que você estivesse usando o -lsinalizador e percebesse que a saída estava funcionando, mas seus scripts ainda seriam bloqueados.

Caleb
fonte
3
Se você realmente precisa analisar a saída de ls, a -bopção pode ajudar. Acontece o em nova linha \n, etc.
Mikel