El comando ls funciona de manera diferente según el destinatario

12

¿Cómo lssaben los comandos como cuál es su stdout?

Parece lsque funciona de manera diferente dependiendo de cuál sea el stdout objetivo. Por ejemplo si lo hago:

ls /home/matt/tmp 

el resultado es:

a.txt b.txt c.txt

Sin embargo si lo hago

ls /home/matt/tmp | cat

el resultado es (es decir, nueva línea por resultado):

a.txt
b.txt
c.txt

El proceso se pasa un descriptor de archivo 1 para stdout ¿verdad? ¿Cómo determina cómo formatear el resultado? ¿El descriptor de archivo revela información?

Mâtt Frëëman
fuente
Relacionados con unix.stackexchange.com/q/157285/4671 , unix.stackexchange.com/q/63108/4671 y probablemente otros. Parece ser un tema popular. Esto podría ser un engaño de uno de estos.
Faheem Mitha

Respuestas:

22

El lsprograma utiliza isatty()para saber si fd 1 es un tty o algo más (tubería, archivo, etc.). De man 3 isatty:

int isatty(int fd);

DESCRIPCIÓN
La isatty()función comprueba si se fdtrata de un descriptor de archivo abierto que se refiere a un terminal


Actualización: Línea 1538 ls.cdesde coreutils (revisión git 43a987e1):

  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }

( many_per_linedebe ser autodescriptivo)

Stéphane Gimenez
fuente
8

No es una respuesta exacta sino una ejemplificación. En un script Bash puedes lograr un efecto similar con test/ [['s -t:

-t FD True if FD is opened on a terminal.

Usándolo así:

bash-4.2$ where() { [[ -t 1 ]] && echo 'my output goes to TTY' || echo 'my output is redirected'; }

bash-4.2$ where
my output goes to TTY

bash-4.2$ where | cat
my output is redirected

bash-4.2$ where > test.file
bash-4.2$ cat test.file
my output is redirected
hombre trabajando
fuente
6

Del ls(1) manual de OpenBSD :

Por defecto, ls enumera una entrada por línea a la salida estándar; las excepciones son a terminales o cuando se especifican las opciones -C, -m o -x.

Entonces despúes:

-1 (El dígito numérico `` uno ''). Fuerza la salida a ser una entrada por línea. Este es el valor predeterminado cuando la salida no es a un terminal.

[...]

-C Fuerza salida de columnas múltiples; Este es el valor predeterminado cuando la salida es a un terminal.

Kusalananda
fuente
1

Puede ejecutar lsen un pseudo-terminal usando el script comando, canalizar la salida de lsotro comando y obtener el mismo formato de salida como si no hubiera tal tubería del flujo stdout, es decir, como si stdout fuera un terminal (tty).

Para el subyacente isatty()mecanismo ya se ha señalado por Stéphane Giménez ver ls.c .

ls -G /
ls -G / | cat
script -q /dev/null ls -G / | sed $'s/\r$//g' | cat

# tty | cat
# script -q /dev/null tty | cat
ron
fuente