Forçar script bash para usar tee sem canalizar a partir da linha de comando

16

Eu tenho um script bash com muitos resultados e gostaria de alterar esse script (não criar um novo) para copiar toda a saída para um arquivo, exatamente como aconteceria se eu estivesse colocando o resultado no tee.

Eu tenho um arquivo script.sh :

#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT
launch_applications_that_output_to_STDOUT
fini

e eu gostaria de fazer uma cópia do STDOUT para um arquivo script.log sem ter que digitar ./script.sh | tee script.log todas as vezes.

Obrigado Tom

    
por Tom 23.12.2009 / 15:59

7 respostas

15

Eu não consegui fazer a linha simples de Dennis funcionar, então aqui está um método muito mais complicado. Eu tentaria o primeiro dele.

Como mencionado, você pode usar exec para redirecionar erro padrão & padrão para o script inteiro. Como assim: exec > $LOGFILE 2>&1 Isso irá mostrar stderr e stdout para $ LOGFILE.

Agora, desde que você queira que isso seja exibido no console, bem como um arquivo de log, você também terá que usar um pipe nomeado para que o exec grave e tee para ler. (O one-liner de Dennis faz isso tecnicamente também, embora obviamente de uma maneira diferente) O próprio pipe é criado com mkfifo $PIPEFILE . Então faça o seguinte.

# Start tee writing to a logfile, but pulling its input from our named pipe.
tee $LOGFILE &lt $PIPEFILE &

# capture tee's process ID for the wait command.
TEEPID=$!

# redirect the rest of the stderr and stdout to our named pipe.
exec > $PIPEFILE 2>&1

echo "Make your commands here"
echo "All their standard out will get teed."
echo "So will their standard error" >&2

# close the stderr and stdout file descriptors.
exec 1>&- 2>&-

# Wait for tee to finish since now that other end of the pipe has closed.
wait $TEEPID

Se você deseja ser minucioso, pode criar e destruir o arquivo de pipe nomeado no início e no final do script.

Para o registro, eu peguei a maior parte deste post muito informativo de um cara aleatório: (Arquivado a versão )

    
por 23.12.2009 / 17:46
21

Basta adicionar isso ao início do seu script:

exec > >(tee -ia script.log)

Isso anexará todas as saídas enviadas ao stdout ao arquivo script.log , deixando o conteúdo anterior no lugar. Se você quiser começar do zero toda vez que o script for executado, basta adicionar rm script.log antes que o comando exec ou remova o -a do comando tee .

A opção -i faz com que tee ignore os sinais de interrupção e pode permitir que tee capture um conjunto de resultados mais completo.

Adicione esta linha para também capturar todos os erros (em um arquivo separado):

exec 2> >(tee -ia scripterr.out)

Os espaços entre os vários símbolos > são importantes.

    
por 23.12.2009 / 17:32
5

Esta é a versão combinada da resposta postada por Dennis Williamson anteriormente. Acrescenta ambos err & std out para script.log na ordem certa.

Adicione esta linha ao início do seu script:

exec > >(tee -a script.log) 2>&1

Observe o espaço entre os sinais > . Funciona para mim no GNU bash, versão 3.2.25 (1) -release (x86_64-redhat-linux-gnu)

    
por 18.11.2010 / 20:47
5

Suponho que outra abordagem seja algo assim:

#!/bin/bash

# start grouping at the top
{ 
    # your script goes here
    do_something_that_outputs_stuff_to_STDOUT
    launch_applications_that_output_to_STDOUT

# and at the bottom, redirect everything from the grouped commands
} 2>&1 | tee script.log 
    
por 17.05.2011 / 17:37
3

Se você quiser uma cópia da saída, você pode usar tee desta maneira:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT | tee script.log
  launch_applications_that_output_to_STDOUT | tee -a script.log
  fini

Isso somente registrará stdout para script.log. Se você quiser ter certeza de que tanto o stderr quanto o stdout sejam redirecionados, use:

  #!/bin/bash
  init
  do_something_that_outputs_stuff_to_STDOUT 2>&1 | tee script.log
  launch_applications_that_output_to_STDOUT 2>&1 | tee -a script.log
  fini

Você pode até torná-lo um pouco melhor com uma pequena função:

  #!/bin/bash

  LOGFILE="script.log"
  # Wipe LOGFILE if you don't want to add to it at each run
  rm -f "$LOGFILE"

  function logcmd() {
        local cmd="$1" logfile=${LOGFILE:-script.log} # Use default value if unset earlier

        # Launch command, redirect stderr to stdout and append to $logfile
        eval '$cmd' 2>&1 | tee -a "$logfile"
  }

  init
  logcmd "do_something_that_outputs_stuff_to_STDOUT"
  logcmd "launch_applications_that_output_to_STDOUT"
  fini
    
por 23.12.2009 / 17:01
0
#!/bin/bash
init
do_something_that_outputs_stuff_to_STDOUT > script.log 2>&1
launch_applications_that_output_to_STDOUT >> script.log 2>&1
fini

Você pode ver mais sobre como funciona aqui: link

    
por 23.12.2009 / 16:05
0

Você só usaria isso:

script logfile.txt
your script or command here

Isso gera tudo para esse log, tudo, além de exibi-lo na tela. Se você quiser a saída FULL, é assim que você faz.

E você pode reproduzir o script se estiver com preguiça.

    
por 23.09.2015 / 15:51

Tags