Como canalizar stdout enquanto o mantém na tela? (e não para um arquivo de saída)

234

Gostaria de canalizar a saída padrão de um programa, mantendo-o na tela.

Com um exemplo simples ( echouse aqui é apenas para fins ilustrativos):

$ echo 'ee' | foo
ee <- a saída que eu gostaria de ver

Eu sei que tee poderia copiar stdout para arquivo, mas não é isso que eu quero.
$ echo 'ee' | tee output.txt | foo

Eu tentei,
$ echo 'ee' | tee /dev/stdout | foomas ele não funciona, pois a saída do tee /dev/stdouté canalizada parafoo

gentooboontoo
fonte
6
Observe que isso echo 'ee' | tee /dev/stderrfunciona, portanto, se o seu requisito "na tela" também for atendido pelo stderr, isso funcionará.
nh2 26/03

Respostas:

344

Aqui está uma solução que funciona em qualquer implementação Unix / Linux, assumindo que ela se preocupa em seguir o POSIXpadrão. Também funciona em alguns ambientes não Unix cygwin.

echo 'ee' | tee /dev/tty | foo

Referência: The Open Group Base Specifications Edição 7 IEEE Std 1003.1, 2013 Edition, §10.1 :

/ dev / tty

Associado ao grupo de processos desse processo, se houver. É útil para programas ou procedimentos de shell que desejam garantir a gravação de mensagens ou a leitura de dados do terminal, independentemente de como a saída foi redirecionada. Também pode ser usado para aplicativos que exigem o nome de um arquivo para saída, quando a saída digitada é desejada e é cansativo descobrir qual terminal está atualmente em uso. Em cada processo, um sinônimo para o terminal de controle

Foi relatado que alguns ambientes como o Google Colab não implementam /dev/ttyenquanto ainda têm seu ttycomando retornando um dispositivo utilizável. Aqui está uma solução alternativa:

tty=$(tty)
echo 'ee' | tee $tty | foo

ou com uma concha Bourne antiga:

tty=`tty`
echo 'ee' | tee $tty | foo
jlliagre
fonte
5
@static_rtti Por que você está ignorando ano após ano minhas respostas ao seu comentário?
Jlliagre
1
@PaulBissex /dev/ttyé um dispositivo Unix obrigatório. Você está correndo em uma prisão BSD?
Jlliagre
1
@PaulBissex Isso é uma falha de implementação ou configuração. O / dev está montado? O que mostra "ls -l / dev / tty / dev / tty * / dev"? Veja lists.freebsd.org/pipermail/freebsd-bugs/2012-November/… forums.freebsd.org/threads/…
jlliagre
1
E você pode cascatear teeassim: cat some.log | tee /dev/tty | tee -a other.log | grep -i 'foo' >> foo.logpara 1) colocar tudo no console, 2) colocar tudo anexado a outro arquivo, 3) colocar as foolinhas em um arquivo diferente.
Jesse Chisholm
1
O Google Colab não possui /dev/tty, mas a saída de ttyé utilizável.
Tom Hale
69

Outra coisa a tentar é:

echo 'ee' | tee >(foo)

O >(foo)é uma substituição de processo .

bmk
fonte
1
e se eu quiser canalizar a saída de foo para outra barra?
Jack Tang
3
@ JackTang - Eu acho que qualquer canalização adicional na saída footerá que fazer parte da substituição do processo. Aqui está um exemplo:echo 'ee' | tee file.txt >(wc -c | tr -d ' ')
Nick Chammas
1
Esta foi a solução para mim no FreeBSD (não / dev / tty)
Paul Bissex
9
@ Nick Chammas, para manter um gasoduto normal, você pode trocar as saídas do tee: echo 'ee' | tee >(cat) | foo | bar.
Vaelus
18

O acesso a "/ dev / stdout" é negado em alguns sistemas, mas o acesso ao terminal do usuário é dado por "/ dev / tty". Usando "wc" para "foo", os exemplos acima funcionam bem (no linux, OSX, etc.) como:

% echo 'Hi' | tee /dev/tty | wc Hi 1 1 3

Para adicionar uma contagem na parte inferior de uma lista de arquivos correspondentes, uso algo como:
% ls [A-J]* | tee /dev/tty | wc -l

Para evitar ter que lembrar de tudo isso, defino aliases:
% alias t tee /dev/tty
% alias wcl wc -l

para que eu possa simplesmente dizer:
% ls [A-J]* | t | wcl


POSTSCRIPT: Para os mais jovens, que podem rir de sua pronúncia como "titty", devo acrescentar que "tty" já foi a abreviação comum de um terminal de "teletipo", que usava um rolo de papel amarelo e tinha teclas redondas que frequentemente preso.

user51527
fonte
17

Experimentar:

$ echo 'ee' | tee /dev/stderr | foo

Se o uso do stderr é uma opção, é claro.

Jan
fonte
8

primeiro, você precisa descobrir o terminal associado à sua tela (ou a tela em que deseja que a saída seja exibida):

tty

então você pode conectar a saída a esse terminal e canalizar a outra cópia através do seu programa foo:

echo ee | tee /dev/pty/2 | foo
Michael Martinez
fonte
1
oneliner: t = $ (tty) eco ee | tee $ t | foo | bar
Jack Tang
5
@ JackTang Isso é realmente melhor, mas té inútil. Você pode usar, echo ee | tee $(tty) | foomas ele ainda possui um comando inútil ( tty), dado que /dev/ttysimplesmente funciona.
Jlliagre 24/10/2014