Linux / Comando tee: mostrar e salvar a saída de um pipeline

tee copia a entrada padrão para a saída padrão e para um ou mais arquivos ao mesmo tempo. Assim, você pode acompanhar a saída de um comando enquanto a salva, ou registrar uma etapa intermediária de um pipeline. Por padrão, tee sobrescreve o arquivo de destino; use -a para acrescentar ao final.

A saída padrão vai para a tela quando não há outro comando ou redirecionamento depois de tee. Se houver um próximo comando no pipeline, esse comando recebe a cópia; o conteúdo do arquivo pode ser maior do que a parte mostrada na tela. O erro padrão é um fluxo separado e precisa ser encaminhado explicitamente quando também deve ser salvo.

Sintaxe e cuidado com sobrescrita

comando | tee [opção...] arquivo [arquivo...]

Essa linha descreve a sintaxe: substitua comando, opções e nomes pelos valores desejados. O pipe (|) envia a saída padrão do comando anterior à entrada de tee. Você pode informar vários arquivos de destino. Consulte tee --version, tee --help ou man tee; as opções deste guia seguem o GNU Coreutils.

Escolha um destino novo para preservar um arquivo existente, ou use -a quando acrescentar for o comportamento pretendido. O ajuste de shell set -C, também chamado noclobber, protege certos redirecionamentos feitos pelo shell; ele não impede tee de abrir e sobrescrever um arquivo passado como argumento. Confirme o destino e guarde uma cópia de dados importantes antes de substituí-los.

Preparar os dados e salvar a saída de date

Em um terminal Bash dedicado ao exercício, execute o bloco inteiro em uma pasta onde possa criar arquivos. Ele cria uma pasta exclusiva, prepara names.txt e grava a data em run-time.txt. && interrompe as próximas etapas da preparação se houver uma falha. Continue na mesma sessão, dentro dessa pasta.

tee_demo=$(mktemp -d ./tee-demo.XXXXXX) &&
cd "$tee_demo" &&
export LC_ALL=C &&
printf 'Zeca\nAna\nBia\n' > names.txt &&
date | tee run-time.txt

A data e a hora mostradas na tela são as mesmas gravadas em run-time.txt. O texto exato depende do relógio e do fuso do ambiente; não espere uma data fixa. Confira com cat run-time.txt. O ajuste export LC_ALL=C mantém o mesmo ambiente para a ordenação dos próximos exemplos; ao fechar a sessão dedicada, ele deixa de afetar comandos futuros.

Acrescentar outra linha com -a

Execute novamente date, acrescentando sua saída ao arquivo já criado:

date | tee -a run-time.txt

A tela mostra somente a nova linha de data. O arquivo passa a conter a linha anterior e a nova, nessa ordem. cat run-time.txt permite conferir ambas. Se você repetir a versão sem -a, o arquivo será substituído pela nova saída. As datas podem ser iguais se os comandos forem executados muito próximos.

Salvar uma etapa intermediária e continuar o pipeline

names.txt contém Zeca, Ana e Bia, nessa ordem. Para ordenar, salvar o resultado e enviar a saída para head:

sort names.txt | tee names.sorted | head

A saída mostra Ana, Bia e Zeca, uma por linha, e names.sorted contém essas mesmas três linhas. O comando sort ordena; tee grava e encaminha; head mostra as primeiras dez linhas por padrão. Neste arquivo de três linhas, head lê a entrada toda.

Com uma entrada grande, head pode encerrar antes de ler tudo. O GNU tee pode então encontrar um pipe fechado e terminar antes de concluir a gravação no arquivo. Se a intenção é continuar gravando mesmo quando o consumidor do pipe sai cedo, use tee -p, por exemplo sort names.txt | tee -p names-complete.sorted | head. A opção ajusta o tratamento do erro de pipe e permite continuar nas saídas restantes; ela não corrige falhas do comando que produz os dados nem erros de gravação em disco.

Conferir uma saída determinística

Para comparar diretamente o conteúdo enviado à tela e ao arquivo, use uma linha fixa:

printf 'status=ok\n' | tee result.txt

A tela e result.txt recebem:

status=ok

Confira com cat result.txt. Depois, printf 'status=done\n' | tee -a result.txt mostra status=done e acrescenta essa segunda linha ao arquivo. Para criar duas cópias novas da mesma saída, printf 'status=ok\n' | tee copy-a.txt copy-b.txt grava uma linha em cada arquivo e também a mostra na saída padrão.

Incluir o erro padrão quando necessário

No Bash, (printf 'ok\n'; printf 'erro\n' >&2) | tee stdout.log grava somente ok em stdout.log. O texto erro continua no erro padrão do grupo de comandos e pode aparecer no terminal sem ter sido salvo nesse arquivo.

Para reunir os dois fluxos antes de tee, use (printf 'ok\n'; printf 'erro\n' >&2) 2>&1 | tee combined.log. Nesse exemplo sequencial, combined.log contém ok e erro, uma linha por mensagem, e ambas também seguem pela saída padrão. Em programas com execução concorrente ou buffers próprios, a ordem das mensagens observadas pode depender do programa.

Verificar falhas do pipeline

No Bash, o status de um pipeline normalmente vem do último comando. Assim, um head bem-sucedido pode esconder uma falha anterior em tee. Imediatamente após o pipeline, printf '%s\n' "${PIPESTATUS[@]}" mostra os status individuais, na ordem dos comandos. Execute essa consulta antes de qualquer outro comando, pois o array PIPESTATUS é atualizado a cada execução.

Para fazer o status geral considerar falhas anteriores, você pode usar (set -o pipefail; sort names.txt | tee -p names-complete-checked.sorted | head). O ajuste vale apenas para o subshell entre parênteses. Em seguida, consulte echo "$?" imediatamente. Um status 0 indica sucesso dos comandos desse pipeline, mas a validade dos dados ainda depende do produtor e da tarefa. Quando for essencial guardar toda a saída, confira também o arquivo produzido.

Na verificação com GNU tee 8.32 no Bash do Git para Windows, foram conferidos gravação, acréscimo, múltiplas saídas, separação dos fluxos, falha ao abrir um destino e o comportamento de um consumidor que termina cedo. A semântica de -p e os recursos do shell devem ser conferidos na implementação usada no seu sistema.

Entender permissões e o uso de sudo

Em um sistema Linux com sudo configurado, o padrão descritivo comando | sudo tee arquivo faz tee abrir o destino com os privilégios concedidos por sudo. Já em sudo comando > arquivo, o redirecionamento é feito pelo shell atual antes de executar o comando com sudo, e pode falhar por falta de permissão.

Esse uso exige autorização para o comando e cuidado com o destino: tee continua sobrescrevendo por padrão, e a elevação não corrige um caminho errado. A entrada também segue para a saída padrão. Se a cópia na tela for indesejada, redirecione a saída de tee para /dev/null no ambiente Linux. Verifique o resultado e evite enviar dados que não devem aparecer no terminal ou nos registros.

Opções principais

Opção Uso
-a Acrescenta ao final dos destinos em vez de sobrescrevê-los.
-i Ignora o sinal de interrupção; não é uma opção geral para ignorar erros.
-p No GNU tee, ajusta o tratamento de erros de pipe para continuar em saídas restantes quando apropriado.

Pergunta frequente

tee salva o erro padrão automaticamente?

Não. Ele copia apenas o que recebe na entrada padrão. Se também quiser gravar o erro padrão do comando anterior, reúna esse fluxo à saída padrão antes do pipe com o redirecionamento adequado, como 2>&1 no Bash, e confira o arquivo resultante.

Documentação oficial

Consulte a página de manual de tee publicada pelo Debian, a documentação do GNU tee e as explicações do Bash sobre pipelines e pipefail e redirecionamentos.