Coloque um texto na frente de cada nova linha que um programa imprima em stdout

9

Então, eu quero fazer um log e, portanto, colocar uma data na frente da saída de um script do bash. O problema é que possui várias linhas de saída. Só consigo colocar a data antes de toda a saída. Mas então eu tenho uma linha sem uma data nos logs. É claro que posso assumir que a data da linha acima é a mesma, mas eu esperava que houvesse uma solução. Desde já, obrigado!

Este é o meu script que chama outro script:

#!/bin/sh
echo $(date "+%F %T") : starting script
echo $(date "+%F %T") : $(./script.sh)
echo $(date "+%F %T") :script ended

Esta é a saída:

2012-07-26 15:34:12 : starting script
2012-07-26 15:35:14 : First line of output
second line of output
2012-07-26 15:35:17 : script ended

E é isso que eu gostaria de ter:

2012-07-26 15:34:12 : starting script
2012-07-26 15:35:14 : First line of output
2012-07-26 15:35:15 : second line of output
2012-07-26 15:35:17 : script ended
tzippy
fonte
Acho que você não pode mudar o segundo script?
22412 jmetz #
Nah, infelizmente não. Por isso vim aqui.
23412 tzippy

Respostas:

9

De acordo com uma pergunta semelhante no Stack Overflow , existem 2 ótimas opções.

awk ( resposta )

<command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; }'

anotar ( resposta )

annotate é um pequeno script bash, que pode ser obtido diretamente através do link fornecido aqui ou, em sistemas baseados no Debian, através do pacote devscripts(na forma de annotate-output).

Oliver Salzburg
fonte
3

Eu acho que você pode usar o awk para isso:

./script.sh | awk '{ print strftime()" : "$0; }'

(consulte http://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html para formatar a data retornada por strftime ())

Flinth
fonte
2
awk: calling undefined function strftime- isso é específico gawk?
Daniel Beck
Agora que você mencionou, sim, parece ser: /
Flinth
2

Você pode usar awk

./script.sh | awk '{ print d,$1}' "d=$(date "+%F %T")"

awkpega um fluxo de entrada e modifica sua saída. Esse script está dizendo "imprima d seguido da saída original" e preencha dcom a data.

Paulo
fonte
11
Isso não avalia a dateexpressão apenas uma vez também, para que todas essas linhas sejam impressas ao mesmo tempo?
Daniel Beck
@DanielBeck Sim, é verdade - Eu tinha assumido que estava pegando a data de cada vez, mas acabou meu teste rápido o suficiente
Paul
1

Isso imprimirá a data e a hora atuais antes de cada linha de saída de ./script.sh:

set -f
./script.sh | while read -r LINE; do echo $(date "+%F %T") : "$LINE"; done
set +f

Como funciona

  • set -fdesativa a expansão do bash (ou echo *não imprimiria um asterisco real).

  • while read -r LINE; do ... donesalva uma linha de saída na variável $LINEe é executada ..., até que todas as linhas sejam processadas.

  • eco $ (data "+% F% T"): "$ LINE" imprime a linha com a hora e a data atuais.

  • set +f ativa novamente a expansão do bash, para que não interfira no restante do script do bash.

Dennis
fonte
Ele é avaliado apenas uma vez, para que cada um sedinsira a mesma data, imediatamente antes de iniciar o segundo script. Provavelmente não o que o usuário quer ...
Daniel Beck
Também não acho que essa tentativa funcione. AFAIK, todo o subshell é avaliado completamente primeiro e depois o loop é percorrido. Então agora os tempos são após a execução.
Daniel Beck
Seu exemplo não funciona, pois você atrasa apenas a saída, não a execução de ls. Apenas tente seu script com o seguinte script.sh: #!/bin/bash(nova linha)echo 1 ; sleep 1 ; echo 2 ; sleep 2 ; echo 3 ; sleep 3 ; echo 4
Daniel Beck
Use readcom um whileloop em vez de um loop for.
26412 chepner
@chepner: Boa ideia.
Dennis