copia a saída consumida para stdout quando o stdout é redirecionado para um arquivo

6

Dado um comando cuja saída está sendo processada, por exemplo, grep, eu também quero que a saída real seja incluída no arquivo de log para fins de depuração.

Por exemplo, se eu tiver o seguinte

useful=$(curl -s http://example.com/some/data | grep 'useful line')
echo "useful=$useful"

Eu quero ver

This page has a number of lines in it, but'
useful lines are the only ones I care about
except when something goes wrong and then
I'd really like to see what the heck was in
the output that grep consumed.
useful=useful lines are the only ones I care about

Isso pode ser feito com tee assim

useful=$(curl -s http://example.com/some/data | tee /proc/$$/fd/1 | grep 'useful line')
echo "useful=$useful"

mas se o stdout estiver sendo redirecionado para um arquivo tee sobrecarrega o resto do seu arquivo de log. tee -a falha basicamente da mesma maneira.

    
por ajorg 26.08.2011 / 21:54

5 respostas

1

tee o fluxo stdout para o dispositivo terminal de controle /dev/tty .

(
exec 1> >(tee -a stdout.log)
: > stdout.log
#var="$(echo -e "one\ntwo" | tee /dev/tty | grep one)"
var="$(echo -e "one\ntwo" | tee -a /dev/tty stdout.log | grep one)"
echo "var=$var"
)

cat stdout.log
# one
# two
# var=one
    
por 27.08.2011 / 13:37
1

Eu não estou certo se você quer $ var, ou se $ var é apenas um meio para um fim. Para obter $ var, adicione var="$(cat log)"

sed -nre 'p;/one/w log' <(echo -e "one\ntwo")
  • ------- (stdout)
    um
    dois
  • ------- (log)
    um

Ou você quer dizer algo assim:

sed -nre 'p;/one/w log' -e 's/one/logged: &/p' <(echo -e "one\ntwo")
  • ------- (stdout)
    um
    logado: um
    dois
  • ------- (log)
    um

Nota: o comando w do sed sobrescreve log cada vez que o script é executado. Você pode, é claro, anexar log a um log principal após a execução do sed. Veja: Resumo de Comandos para sed

    
por 27.08.2011 / 15:54
0

Por que não usar apenas uma função:

#!/bin/bash
logAndEcho () {
    echo -e "$@" >> LOGFILE.txt
    echo -e "$@"
}
var=$(logAndEcho "one\ntwo\nThis is a test"|grep one)
echo "var=$var"

Isso enviará os resultados inteiros para o arquivo de log e, em seguida, ecoará os dados para stdin, onde você poderá capturá-lo conforme necessário.

    
por 27.08.2011 / 13:21
0

Acho que você precisa usar um descritor de arquivo adicional e tee the stdout stream para que o fluxo stdout duplicado possa ser redirecionado para um arquivo de log. Desta forma, o fluxo normal stdout via /proc/$$/fd/1 é deixado inalterado. E se grep falhar em corresponder a uma linha, você deverá ter toda a saída de comando que o grep consumiu disponível em seu arquivo de log para fins de depuração.

useful="$(
exec 3<&1 3>stdout.log
curl -s http://example.com/some/data | tee /proc/$$/fd/3 | grep 'useful line'
exec 3<&-
)"
echo "useful=$useful"


# test case
(
# dup stdout using tee & an additional file descriptor
# open fd 3 for reading from where fd 1 is pointing to (i.e. stdout)
# anything that is being redirected to fd 3 will be redirected to stdout.log 
#exec 3<&1 3>stdout.log
exec 3<&1 3> >(tr '[:lower:]' '[:upper:]' > stdout.log)
echo -e "one\ntwo" | tee /dev/fd/3 | grep one        # Mac OS X
#echo -e "one\ntwo" | tee /proc/$$/fd/3 | grep one   # Linux
exec 3<&-
) 

Outra abordagem pode ser usar pipes nomeados ou Co-Processos Bash (disponível no Bash 4.0 e acima).

Para obter mais informações sobre os descritores de arquivos, consulte: Descritor de Arquivo 101

    
por 31.08.2011 / 12:24
0

sed é projetado para isso - é o editor de fluxo. Ele pode substituir tee e grep em seu processo, ou ser combinado com tee para mais alguns dentes em seu fork, se você quiser. Enfim, veja por si mesmo:

% sed '/useful/w ./useful.log' <<HDOC >>./notsomuch.log
> maybe useful
> definitely not
> ho-hum
> now this is useful
> HDOC
% cat ./useful.log
OUT> maybe useful
OUT> now this is useful
% cat ./notsomuch.log
OUT> maybe useful
OUT> definitely not
OUT> ho-hum
OUT> now this is useful
    
por 05.03.2014 / 15:23

Tags