ls comando operando de forma diferente dependendo do destinatário

11

Como comandos como ls sabem o que é stdout?

Parece que ls está operando de forma diferente dependendo de qual é o stdout de destino. Por exemplo, se eu fizer:

ls /home/matt/tmp 

o resultado é:

a.txt b.txt c.txt

No entanto, se eu fizer

ls /home/matt/tmp | cat

o resultado é (ou seja, nova linha por resultado):

a.txt
b.txt
c.txt

O processo é passado um descritor de arquivo 1 para stdout certo? Como isso determina como formatar o resultado? O descritor de arquivo revela informações?

    
por Mâtt Frëëman 06.10.2011 / 16:12

4 respostas

20

O programa ls usa isatty() para saber se o fd 1 é um tty ou algo diferente (canal, arquivo, etc…). De man 3 isatty :

int isatty(int fd);

DESCRIPTION
The isatty() function tests whether fd is an open file descriptor referring to a terminal

Updade: Linha 1538 em ls.c do coreutils (revisão do git 43a987e1):

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

( many_per_line deve ser autodescritivo.)

    
por 06.10.2011 / 16:19
6

Do manual do OpenBSD ls(1) :

By default, ls lists one entry per line to standard output; the exceptions are to terminals or when the -C, -m, or -x options are specified.

Então, mais tarde:

-1 (The numeric digit ''one''.) Force output to be one entry per line. This is the default when output is not to a terminal.

[...]

-C Force multi-column output; this is the default when output is to a terminal.

    
por 06.10.2011 / 16:25
6

Não é uma resposta exata, mas uma exemplificação. Em um script de Bash, você pode obter um efeito semelhante com test / [[ ' -t :

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

Usando assim:

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
    
por 06.10.2011 / 16:59
1

Você pode executar ls em um pseudo-terminal usando o comando script , canalizar a saída de ls para outro comando e obter o mesmo formato de saída como se não houvesse essa canalização do fluxo stdout, ou seja como se stdout fosse um terminal (tty).

Para o mecanismo isatty() subjacente já apontado por Stéphane Gimenez, veja 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
    
por 06.10.2011 / 19:43