La salida de ls tiene líneas nuevas pero se muestra en una sola línea. ¿Por qué?

41

Creo que puedo estar pasando por alto un punto relativamente fundamental con respecto a Shell. La salida del comando ls por defecto separa la salida con nuevas líneas, pero el shell muestra la salida en una sola línea.

¿Puede alguien explicarme esto? Siempre había supuesto que la salida estaba simplemente separada por espacios, pero ahora que veo la salida separada por nuevas líneas, esperaría que la salida se muestre en líneas separadas.

Ejemplo:

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

od muestra que la salida está separada por nuevas líneas:

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 hay nuevas líneas, entonces ¿por qué la salida no se muestra como:

text1 
text2
text3
zod90
fuente

Respuestas:

44

Cuando se canaliza la salida, lsactúa de forma diferente.

Este hecho está oculto en la documentación de información :

Si la salida estándar es una terminal, la salida está en columnas (ordenadas verticalmente) y los caracteres de control se muestran como signos de interrogación; de lo contrario, la salida aparece una por línea y los caracteres de control se muestran tal cual.

Para probarlo, intenta correr

ls

y entonces

ls | less

Esto significa que si desea garantizar que el resultado sea un archivo por línea, independientemente de si se está canalizando o redirigiendo, debe ejecutar

ls -1

( -1es el número uno)

O puede forzar la ls | lesssalida en columnas ejecutando

ls -C

( -Ces una C mayúscula)

Mikel
fuente
66
@theconnorpower: es bastante específico para ls. Es útil, pero es claramente inconsistente y sorprendente. Pero tenga en cuenta que algunos comandos que producen resultados en color eliminarán los colores cuando se canalicen también.
Mikel
55
@theconnorpower: Trivia: los inventores de Unix escribieron Plan9. En Plan9, lssiempre imprime uno por línea y lcsiempre imprime en columnas.
Mikel
2
@theconnorpower: También hay programas que leen el tamaño del terminal y ajustan su salida en consecuencia, por ejemplo, en Debian dpkg -lusará todo el ancho de la pantalla, pero si se imprime en una tubería, se supone que el terminal tiene 80 columnas de ancho , y abrevia la salida para que se ajuste si es necesario.
Mikel
1
@Mikel Interesante escuchar las diferencias ls / lc en Plan9. Gracias por la respuesta detallada.
zod90
1
¿Cómo puede un programa determinar si su salida se redirige a un archivo o si va a un shell?
user2820379
4

Su descubrimiento destaca la razón principal por la que analizar la salida de lssiempre es una mala idea. Vea la wiki de Greg para una explicación completa .

Piensa en tu problema a la inversa. Notó que ls a veces imprime y a veces no imprime nuevas líneas entre su salida. Para usar en scripts o cuando la -1bandera lo fuerza , lo hace. Una nueva línea al final de cada archivo. Lo que no hay garantía de que cada nueva línea represente un nuevo nombre de archivo . De hecho, si un nombre de archivo contiene una nueva línea en sí, la salida de ls será absolutamente irreparable. Considere estos nombres de archivo:

file1
file2\nfile3
file4

Cuando tienes ls -1un directorio con eso, obtienes algo que se ve así:

file1
file2
file3
file4

¿No asumirías naturalmente que había cuatro archivos? También lo haría cualquier script que analice la salida de ls. En realidad, hay tres archivos, uno de ellos con un nombre complicado, pero no podrá resolverlo a partir de la salida de ls. *

* A menos que estuvieras usando la -lbandera y notaras que la salida estaba borrada, pero tus scripts aún se ahogarían.

Caleb
fuente
3
Si realmente tiene que analizar la salida de ls, la -bopción puede ayudar. Convierte la nueva línea en \n, etc.
Mikel