redireccionar y registrar la salida del script

8

Estoy tratando de ordenar los siguientes fragmentos, los objetivos de diseño son registrar toda la salida de un script y no debería ser un contenedor. Menos líneas son mejores.

No me importan las entradas del usuario (en esta etapa), los scripts de destino se ejecutan de forma no interactiva.

El fragmento necesita

  • salida stdout para iniciar sesión, y siempre hacer eco a la consola
  • salida stderr para iniciar sesión y echo a la consola si la depuración está habilitada
  • Los mensajes stderr deben ir precedidos de marcas de tiempo y otra utilidad

Por el momento tengo lo siguiente que solo se prueba en versiones recientes de bash (4.2+?) Como en Ubuntu preciso, pero se porta mal en 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}

Luego esto...

# 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
}

En lugar de echoque puede llamar a uno de esos procedimientos msg, por ejemplo, msg_con "hello world".
También la producción script luego ir a stderr estableciendo como una variable de entorno en tiempo de llamada, por ejemplo,  DEBUG_TEST=true myscript.

He leído que exec puede no funcionar en algunos shells como busybox. Hay una combinación de mkfifo y fork en https://stackoverflow.com/a/5200754 que hace algo similar, pero prefiero no usar fork a menos que sea absolutamente necesario.

Prefiera los ejemplos de bash, por favor, pero algo que funcione bajo sh o sea más portátil sería bueno. ¿Algunas ideas?

Glenn
fuente

Respuestas:

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) ==="
}

Necesita tener $ logfile establecido en algo

Angelo
fuente
Esto es genial, la forma en que lo estoy leyendo usa gawk para agregar los encabezados de los mensajes. Eso tendrá el efecto secundario adicional de agregarlos a las salidas de comando también.
Glenn
La razón para usar gawk para agregar una marca de tiempo (y un ID de proceso) a cada línea de registro es porque se ejecutará cada vez que se escriba la salida y, por lo tanto, actualice la marca de tiempo. También es importante usar gawk y no awk porque creo que la función strftime es una extensión de GNU.
Angelo
0

exec > filenamedebería funcionar en sh, y realmente funciona en busybox v1.15.3 (noviembre de 2011). Pero la sustitución del proceso no >(command)es portátil ya que es una extensión bash. Solo evita usarlo en scripts. ¿Por qué >>no es suficiente para ti?

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

Otra solución es especificar la redirección fuera de sus scripts. Cuando su script se invoca en segundo plano (por cron, o script del sistema, etc.), debería llamarse así

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

Cuando invoque el script manualmente y desee ver el resultado, simplemente llámelo sin redireccionamientos.

kirikaza
fuente
1
El autor de la pregunta quiere que la salida del script vaya tanto a la consola como al archivo de registro.
0

Estos dos ejemplos harán lo que sus objetivos establecidos son

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

o

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1
Luke
fuente
0

Podría usar el teecomando o el scriptcomando, ambos son realmente útiles.

Falk
fuente
El script se ve genial, pero realmente no hace lo que necesito, el comportamiento tiene que modificarse durante el tiempo de ejecución.
Glenn