menos arquivo1 arquivo2 | gato - por que isso funciona?

21

Quando utilizo less file1 file2, recebo os dois arquivos mostrados no "menos visualizador de buffer", mas less file1 file2 | catimprimo o conteúdo de ambos os arquivos anexados ao stdout. Como menos sabe se deve mostrar o "menos visualizador de buffer" ou produzir saída para stdout para um próximo comando? Que mecanismo é usado para fazer isso?

tfh
fonte

Respostas:

30

lessimprime o texto em stdout. stdout vai

  • para um terminal (/ dev / tty?) e abre o visualizador de buffer padrão
  • através de um tubo ao canalizar para outro programa usando | ( less text | cut -d: -f1)
  • para um arquivo ao redirecioná-lo com> ( less text > tmp)

Existe uma função C chamada "isa tty " que verifica se a saída está indo para um tty (menos 4.81, main.c, linha 112). Nesse caso, ele usa o visualizador de buffer, caso contrário, ele se comporta como cat.

No bash, você pode usar o teste (consulte man test)

  • -t FD descritor de arquivo FD é aberto em um terminal
  • -p FILE existe e é um pipe nomeado

Exemplo:

[[ -t 1 ]] && \
    echo 'STDOUT is attached to TTY'

[[ -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a pipe'

[[ ! -t 1 && ! -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a redirection'
Michael D.
fonte
1
@tfh Se STDOUT não estiver conectado a um canal ou redirecionamento, é correto que eles não imprimam que STDOUT esteja conectado a um canal ou redirecionamento. Coloque todos os três em um script. Chamada bash script.sh, bash script.sh | cat, bash script.sh > file, e ver o que saída que você tem.
hvd
1
stdoutnão é algo que possa ser "gravado em um arquivo". É algo que você write() deve fazer . lessnão precisa fazer nada diferente, dependendo de sua saída ser um arquivo, tubo, soquete ou dispositivo de bloco ou qualquer outra coisa. Só importa que não seja um tty, então apenas se comporta como cat. (Presumo que você soubesse disso e apenas escolhesse as palavras erradas para explicá-lo, mas pensei em apontar isso para outros leitores).
Peter Cordes
Então você quer dizer que é tarefa de menos se comportar como gato na minha pergunta específica - ou mais geral: se comportar como o próximo comando em um pipeline. Pelo que entendi, não posso assumir que o mesmo comportamento seja implementado em uma ferramenta diferente também.
tfh 31/12/16
@tfh: Não, lessnão "descobri" o catpróximo. Ele se comporta como, catindependentemente do que vem a seguir, se o stdout não é um tty.
Peter Cordes
@ MichaelD .: obrigado, corrigi minha resposta. Eu apenas imaginei que lessiria adiante e usaria um TCGETS para obter as dimensões terminais ou descobrir que não é um tty, mas aparentemente eu imaginei errado.
Peter Cordes
6

lessverifica se stdouté um terminal e se comporta como catquando não é (copia stdin para stdout até EOF).

Esse recurso permite que você escreva scripts ou programas que sempre enviam sua saída (por exemplo, --helpsaída) lessenquanto permitem um redirecionamento fácil para um arquivo. Seria péssimo se some_command --fullhelp > help.txtainda esperasse pela barra de espaço no stdin para folhear o texto, ou algo assim. Alguns comandos (por exemplo man) verificam sua própria saída para decidir se devem enviar sua saída através de um pager ou não. Se você executar man ls > ls.txt, ele nunca chamará o seu $PAGER.

lessO comportamento semelhante a um gato é útil se você esquecer de editá-lo em uma única linha ao adicionar mais estágios a um pipeline também.


lessprecisa descobrir as dimensões do terminal (tamanho da tela, para saber quantas linhas mostrar ao mesmo tempo). O que ioctl(2)ele usa stdoutretornaria ENOTTY em um não terminal, portanto não pode evitar o manuseio do caso não terminal. lessrealmente usa isatty(3)antes de verificar as dimensões do terminal, mas isattyfunciona tentando um ioctl somente de tty e verificando a falta de erro.

Até um paginador simples como more(1)(pelo menos a versão util-linux) possui esse recurso, porque é provavelmente o comportamento mais simples possível de implementar nesse caso.


Observe que quando você tubo algo em less (por exemplo grep foo bar.txt | less), ele não tem que abrir /dev/ttypara a entrada do teclado. (Você pode vê-lo fazer isso com echo foo | strace less).

Peter Cordes
fonte