script example español ejemplos definicion shell scripting

example - shell scripting pdf



Cómo agregar la marca de tiempo a la redirección de STDERR (12)

¿En bash / ksh podemos agregar la marca de tiempo al redireccionamiento de STDERR?

Eg myscript.sh 2> error.log

Quiero que se escriba una marca de tiempo también en el registro.


¿Qué hay de timestamping la salida restante, redirigiendo todo a stdout?

Esta respuesta combina algunas técnicas de arriba, así como de unix stackexchange here y here . bash > = 4.2 se supone, pero otros shells avanzados pueden funcionar. Para < 4.2 , reemplace printf con una llamada (más lenta) hasta la date .

: ${TIMESTAMP_FORMAT:="%F %T"} # override via environment _loglines() { while IFS= read -r _line ; do printf "%(${TIMESTAMP_FORMAT})T#%s/n" ''-1'' "$_line"; done; } exec 7<&2 6<&1 exec &> >( _loglines ) # Logit

Para restaurar stdout / stderr:

exec 1>&6 2>&7

A continuación, puede usar tee para enviar las marcas de tiempo a stdout y a un archivo de registro.

_tmpfile=$(mktemp) exec &> >( _loglines | tee $_tmpfile )

No es una mala idea tener código de limpieza si el proceso salió sin error:

trap "_cleanup /$?" 0 SIGHUP SIGINT SIGABRT SIGBUS SIGQUIT SIGTRAP SIGUSR1 SIGUSR2 SIGTERM _cleanup() { exec >&6 2>&7 [[ "$1" != 0 ]] && cat "$_logtemp" rm -f "$_logtemp" exit "${1:-0}" }


Aquí hay una versión que usa un ciclo de while read while como pax , pero no requiere descriptores de archivo adicionales o un script separado (aunque puede usar uno). Utiliza la sustitución de procesos:

myscript.sh 2> >( while read line; do echo "$(date): ${line}"; done > error.log )

Usando predate.sh de pax :

myscript.sh 2> >( predate.sh > error.log )


El paquete devscripts en Debian / Ubuntu contiene un script llamado annotate-output que hace eso (para stdout y stderr).

$ annotate-output make 21:41:21 I: Started make 21:41:21 O: gcc -Wall program.c 21:43:18 E: program.c: Couldn''t compile, and took me ages to find out 21:43:19 E: collect2: ld returned 1 exit status 21:43:19 E: make: *** [all] Error 1 21:43:19 I: Finished with exitcode 2


El programa está en la entrada estándar del paquete moreutils para la salida estándar, y prefija cada línea con una marca de tiempo.

Para prefijar líneas stdout: command | ts command | ts
Para prefijar tanto stdout como stderr: command 2>&1 | ts command 2>&1 | ts


En lugar de escribir una secuencia de comandos para canalizar, prefiero escribir el registrador como una función dentro de la secuencia de comandos, y luego enviar la totalidad del proceso con corchetes, así:

# Vars logfile=/path/to/scriptoutput.log # Defined functions teelogger(){ log=$1 while read line ; do print "$(date +"%x %T") :: $line" | tee -a $log done } # Start process { echo ''well'' sleep 3 echo ''hi'' sleep 3 echo ''there'' sleep 3 echo ''sailor'' } | teelogger $logfile


Era demasiado flojo para todas las soluciones actuales ... Así que descubrí uno nuevo (también se pueden ajustar los trabajos para stdout para stderr ):

echo "output" | xargs -L1 -I{} bash -c "echo /$(date +''%x %T'') ''{}''" | tee error.log

guardaría para archivar e imprimir algo así: 11/3/16 16:07:52 output

Detalles:

-L1 significa "para cada nueva línea"

-I{} significa "reemplazar {} por entrada"

bash -c se usa para actualizar $(date) cada vez para una nueva llamada

%x %T formatea la marca de tiempo en forma mínima.

Debería funcionar como un amuleto si stdout y stderr no tienen comillas ("o`). Si tiene (o podría tener), es mejor usar:

echo "output" | awk ''{cmd="(date +''%H:%M:%S'')"; cmd | getline d; print d,$0; close(cmd)} | tee error.log''

(Tomé de mi respuesta en otro tema: https://.com/a/41138870/868947 )


Esto: nohup myscript.sh 2>> (while read line; echo "$ (date): $ {line}"; done> mystd.err) </ dev / null &

Funciona como tal, pero cuando cierro la sesión y vuelvo a iniciar sesión en el servidor, no funciona. es decir, mystd.err deja de poblarse con la corriente stderr aunque mi proceso (myscript.sh aquí) todavía se ejecuta.

¿Alguien sabe cómo recuperar la stderr perdida en el archivo mystd.err?


Me gustan esos scripts de shell portátiles, pero un poco molestos porque teclean / exec date (1) para cada línea. Aquí hay un rápido perl one-liner para hacer lo mismo de manera más eficiente:

perl -p -MPOSIX -e ''BEGIN {$!=1} $_ = strftime("%T ", localtime) . $_''

Para usarlo, simplemente ingrese esta entrada de comando a través de su stdin:

(echo hi; sleep 1; echo lo) | perl -p -MPOSIX -e ''BEGIN {$|=1} $_ = strftime("%T ", localtime) . $_''


Pensé que agregaría mi valor de 2 centavos.

#!/bin/sh timestamp(){ name=$(printf "$1%*s" `expr 15 - ${#1}`) awk "{ print strftime(/"%b %d %H:%M:%S/"), /"- $name -/", $$, /"- INFO -/", /$0; fflush() }"; } echo "hi" | timestamp "process name" >> /tmp/proccess.log

printf "$ 1% * s" `expr 15 - $ {# 1}`
Separar el nombre para que se vea bien, donde 15 es el espacio máximo emitido, aumentar si se desea

salidas >> Fecha - Nombre del proceso - ID del proceso - INFO - Mensaje

Jun 27 13:57:20 - process name - 18866 - INFO - hi


Si desea redirigir a stdout, descubrí que debe hacer esto:

myscript.sh >> >( while read line; do echo "$(date): ${line}"; done )

No estoy seguro de por qué necesito el > delante del ( , entonces <( , pero eso es lo que funciona.


Si está hablando de una marca de tiempo actualizada en cada línea, eso es algo que probablemente quiera hacer en su secuencia de comandos real (pero consulte a continuación una solución ingeniosa si no tiene poder para cambiarla). Si solo quiere una fecha de marcador en su propia línea antes de que su script comience a escribir, usaría:

( date 1>&2 ; myscript.sh ) 2>error.log

Lo que necesita es un truco para canalizar stderr a través de otro programa que puede agregar marcas de tiempo en cada línea. Podrías hacer esto con un programa en C, pero hay una forma mucho más desviada usando solo bash .

Primero, cree una secuencia de comandos que agregará la marca de tiempo a cada línea (llamada predate.sh ):

#!/bin/bash while read line ; do echo "$(date): ${line}" done

Por ejemplo:

( echo a ; sleep 5 ; echo b ; sleep 2 ; echo c ) | ./predate.sh

produce:

Fri Oct 2 12:31:39 WAST 2009: a Fri Oct 2 12:31:44 WAST 2009: b Fri Oct 2 12:31:46 WAST 2009: c

Entonces necesitas otro truco que pueda cambiar stdout y stderr, esta pequeña monstruosidad aquí:

( myscript.sh 3>&1 1>&2- 2>&3- )

Entonces es simple combinar los dos trucos stdout tiempo stdout y redirigiéndolo a su archivo:

( myscript.sh 3>&1 1>&2- 2>&3- ) | ./predate.sh >error.log

La siguiente transcripción muestra esto en acción:

pax> cat predate.sh #!/bin/bash while read line ; do echo "$(date): ${line}" done pax> cat tstdate.sh #!/bin/bash echo a to stderr then wait five seconds 1>&2 sleep 5 echo b to stderr then wait two seconds 1>&2 sleep 2 echo c to stderr 1>&2 echo d to stdout pax> ( ( ./tstdate.sh ) 3>&1 1>&2- 2>&3- ) | ./predate.sh >error.log d to stdout pax> cat error.log Fri Oct 2 12:49:40 WAST 2009: a to stderr then wait five seconds Fri Oct 2 12:49:45 WAST 2009: b to stderr then wait two seconds Fri Oct 2 12:49:47 WAST 2009: c to stderr

Como ya se mencionó, predate.sh prefijará cada línea con una marca de tiempo y tstdate.sh es simplemente un programa de prueba para escribir en stdout y stderr con intervalos de tiempo específicos.

Cuando ejecuta el comando, en realidad se escribe "d to stdout" en stderr (pero ese es su dispositivo TTY o cualquier cosa que haya sido stdout cuando comenzó). Las líneas stderr marca de tiempo se escriben en su archivo deseado.


#!/bin/bash DEBUG=1 LOG=$HOME/script_${0##*/}_$(date +%Y.%m.%d-%H.%M.%S-%N).log ERROR=$HOME/error.log exec 2> $ERROR exec 1> >(tee -ai $LOG) if [ $DEBUG = 0 ] ; then exec 4> >(xargs -i echo -e "[ debug ] {}") else exec 4> /dev/null fi # test echo " debug sth " >&4 echo " log sth normal " type -f this_is_error echo " errot sth ..." >&2 echo " finish ..." >&2>&4 # close descriptor 4 exec 4>&-