Comando ls operando de maneira diferente, dependendo do destinatário

12

Como comandos como lssabem qual é o seu stdout?

Parece que lsestá operando diferente, dependendo do que 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 recebe um descritor de arquivo 1 para stdout, certo? Como ele determina como formatar o resultado? O descritor de arquivo revela informações?

Mâtt Frëëman
fonte
Relacionados unix.stackexchange.com/q/157285/4671 , unix.stackexchange.com/q/63108/4671 e provavelmente outros. Parece ser um tópico popular. Isso pode ser um engano de um deles.
Faheem Mitha

Respostas:

22

O lsprograma usa isatty()para saber se fd 1 é um tty ou algo mais (pipe, arquivo, etc.). De man 3 isatty:

int isatty(int fd);

DESCRIÇÃO
A isatty()função testa se fdé um descritor de arquivo aberto que se refere a um terminal


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

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

( many_per_linedeve ser auto-descritivo.)

Stéphane Gimenez
fonte
8

Não é uma resposta exata, mas uma exemplificação. Em um script Bash, você pode obter um efeito semelhante com test/ [['s -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
homem a trabalhar
fonte
6

No ls(1) manual do OpenBSD :

Por padrão, ls lista uma entrada por linha na saída padrão; as exceções são para terminais ou quando as opções -C, -m ou -x são especificadas.

Depois, mais tarde:

-1 (O dígito numérico `` um ''.) Força a saída a ser uma entrada por linha. Esse é o padrão quando a saída não é para um terminal.

[...]

-C Força saída multi-coluna; esse é o padrão quando a saída é para um terminal.

Kusalananda
fonte
1

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

Para o subjacente isatty()mecanismo já apontado por Stéphane Gimenez 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
fonte