redirecionar e registrar a saída do script

8

Estou tentando organizar os seguintes trechos, os objetivos de design são registrar toda a saída de um script e não devem ser um invólucro. Menos linhas são melhores.

Não ligo para as entradas do usuário (neste estágio), os scripts de destino são executados de maneira não interativa.

O trecho precisa

  • stdout de saída para log e sempre ecoa no console
  • stderr de saída para log e eco no console se a depuração estiver ativada
  • As mensagens stderr devem ser prefixadas com carimbos de data e hora e outras utilidades

No momento, tenho o seguinte, que só é testado em versões recentes do bash (4.2+?), Como no Ubuntu, precisas, mas se comporta mal no CentOS6.

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
  && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
  || exec 2>> ${DEBUG_LOG}

Então isso...

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
  echo -e "$(date +%T) ${0##*/}: $1" \
    | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
  if [ "${DEBUG_TEST}" = "true" ]; then 
    msg_log "$1"
  else
    echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
  fi
}

Em vez de echoeu posso chamar um desses procedimentos de msg, por exemplo msg_con "hello world",.
Além disso, a saída do script irá para o stderr configurando como uma variável de ambiente no momento da chamada, por exemplo  DEBUG_TEST=true myscript,.

Eu li que o exec pode não funcionar em alguns shells, como o busybox. Existe uma combinação mkfifo e fork em https://stackoverflow.com/a/5200754 que faz algo semelhante, mas eu prefiro não usar fork, a menos que seja absolutamente necessário.

Prefira exemplos do bash, por favor, mas algo que funcione em sh ou seja mais portátil seria bom. Alguma ideia?

Glenn
fonte

Respostas:

1
function startLogging {
    exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
    [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
    echo "=== Log started for $$ at $(date +%F-%T) ==="
}

Você precisa ter $ logfile definido como algo

Angelo
fonte
Isso é legal, do jeito que eu estou lendo, você usa o gawk para adicionar os cabeçalhos das mensagens. Isso terá o efeito colateral adicional de adicioná-los também às saídas de comando.
Glenn
O motivo para usar o gawk para adicionar um registro de data e hora (e identificação do processo) a cada linha de log é porque ele será executado toda vez que a saída for gravada e, portanto, atualizará o registro de data e hora. Também é importante usar o gawk e não o awk, porque acho que a função strftime é uma extensão do GNU.
Angelo
0

exec > filenamedeve funcionar no sh e, na verdade, funciona no busybox v1.15.3 (novembro de 2011). Mas a substituição do processo não >(command)é portável, pois é a extensão do bash. Apenas evite usá-lo em scripts. Por que >>não é suficiente para você?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

Outra solução é especificar o redirecionamento fora dos seus scripts. Quando seu script é chamado em segundo plano (por cron, ou script do sistema etc.), eles devem ser chamados assim

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

Quando você chama o script manualmente e deseja ver a saída, basta chamá-lo sem redirecionamentos.

Kirikaza
fonte
1
O solicitante de pergunta deseja que a saída do script vá para o console e o arquivo de log.
0

Esses dois exemplos farão quais são seus objetivos declarados

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

ou

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1
Lucas
fonte
0

Você pode usar o teecomando ou scriptcomando, ambos são realmente úteis.

Falk
fonte
script parece legal, mas realmente não faz o que eu preciso, o comportamento precisa ser modificado durante o tempo de execução.
Glenn