Cuando tee
termina, el comando que lo alimenta continuará ejecutándose, hasta que intente escribir más resultados. Luego obtendrá un SIGPIPE (13 en la mayoría de los sistemas) por tratar de escribir en una tubería sin lectores.
Si modifica su secuencia de comandos para atrapar SIGPIPE y toma alguna acción apropiada (como dejar de escribir la salida), entonces debería poder continuar después de que termine.
Mejor aún, en lugar de matar a tee
en absoluto, usa logrotate
con el copytruncate
opción por simplicidad.
Para citar logrotate(8)
:
copytruncate
Trunque el archivo de registro original en su lugar después de crear una copia, en lugar de mover el archivo de registro anterior y, opcionalmente, crear uno nuevo. Se puede usar cuando no se le puede decir a algún programa que cierre su archivo de registro y, por lo tanto, podría continuar escribiendo (agregando) al archivo de registro anterior para siempre. Tenga en cuenta que hay un intervalo de tiempo muy pequeño entre la copia del archivo y el truncamiento, por lo que es posible que se pierdan algunos datos de registro. Cuando se utiliza esta opción, la opción de creación no tendrá ningún efecto, ya que el archivo de registro anterior permanece en su lugar.
Explicando el "por qué"
En resumen:si escribe fallando no hacer que un programa salga (por defecto), tendríamos un lío. Considera find . | head -n 10
-- no quieres find
para continuar, escaneando el resto de su disco duro, después de head
ya tomó las 10 líneas que necesitaba y procedió.
Hacerlo mejor:gire dentro de su registrador
Considere lo siguiente, que no usa tee
en absoluto, como ejemplo demostrativo:
#!/usr/bin/env bash
file=${1:-debug.log} # filename as 1st argument
max_size=${2:-100000} # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit # Use GNU stat to retrieve size
exec >>"$file" # Open file for append
while IFS= read -r line; do # read a line from stdin
size=$(( size + ${#line} + 1 )) # add line's length + 1 to our counter
if (( size > max_size )); then # and if it exceeds our maximum...
mv -- "$file" "$file.old" # ...rename the file away...
exec >"$file" # ...and reopen a new file as stdout
size=0 # ...resetting our size counter
fi
printf '%s\n' "$line" # regardless, append to our current stdout
done
Si se ejecuta como:
/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log
...esto comenzará agregando a /tmp/nginx/debug_log
, cambiando el nombre del archivo a /tmp/nginx/debug_log.old
cuando hay más de 100 KB de contenido. Debido a que el registrador mismo está haciendo la rotación, no hay tubería rota, error ni ventana de pérdida de datos cuando se lleva a cabo la rotación; cada línea se escribirá en un archivo u otro.
Por supuesto, implementar esto en bash nativo es ineficiente, pero lo anterior es un ejemplo ilustrativo. Hay numerosos programas disponibles que implementarán la lógica anterior para usted. Considere:
svlogd
, el registrador de servicios de la suite Runit.s6-log
, una alternativa mantenida activamente de la suite skanet.multilog
de DJB Daemontools, el abuelo de esta familia de herramientas de monitoreo y supervisión de procesos.