Después de que tar falla, el script sale sin manejar el error

Después de que tar falla, el script sale sin manejar el error

Entonces, tengo un script de respaldo que se ve así:

tar -cf "${BACKUP_TAR}" "${LATEST_SUCCESSFUL_BACKUP}" 2>&1 | tee -a "${LOG_FILE}"

  local PACKING_EXITCODE=${PIPESTATUS[0]}
  if [ ${PACKING_EXITCODE} -eq 0 ]; then 
    logging 'Packing successful'
  else
    logging "ERROR: Packing failed! ERROR: ${PACKING_EXITCODE}. Disk space?"
    df -h 2>&1 | tee -a "${LOG_FILE}"
    logging "Check the log file: ${LOG_FILE}"
    set_lockfile 'destroy'
    backup_remove_package
    exit 1
  fi

logginges una función para iniciar sesión correctamente en mi archivo de registro.

logging () {
  local now="$(date)"
  local logfile=$2
  local logfile=${logfile:-$LOG_FILE}
  cat <<< "${now} $@" | tee -a "${logfile}"
}

set_lockfile "destroy"` es una función que elimina mi archivo de bloqueo.

set_lockfile () {
  local lockfile_action=$1
  local lockfile=$2
  local lockfile=${lockfile:-$LOCK_FILE}

  if [ "${lockfile_action}" == "create" ]; then
    #...
  elif [ "${lockfile_action}" == "destroy" ]; then
   destroy_lockfile $lockfile
  else
    logging 'ERROR: Wrong argument for locking file: use create or destroy'
    exit 1
  fi
}

destroy_lockfile () {
  local lockfile=$1

  if [ ! -f ${lockfile} ]; then
    logging "WARNING: Lockfile ${lockfile} not found!"
  else
    logging "Removing lockfile ${lockfile}"
    rm -f "${lockfile}"
  fi
}

backup_remove_packagees una función para eliminar cualquier archivo temporal creado.

Experimento un embalaje fallido debido a un disco lleno, comportamiento esperado como puedes adivinar para el archivo df -h.

Lo interesante es el registro de respaldo. Afirma:

tar: /tmp/backup/20180827T223001.tar: Wrote only 4096 of 10240 bytes
tar: Error is not recoverable: exiting now
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1      788G  788G     0 100% /
devtmpfs        3.9G   60K  3.9G   1% /dev
tmpfs           3.9G     0  3.9G   0% /dev/shm

Lo que significa que tarfalló, luego pasó por la ifcondición, de alguna manera se saltó el logging "ERROR: ...", ejecutó el df -hy murió. saltándose el resto.

De alguna manera parece que se está saltando cualquier función pero ejecutando los comandos.

La copia de seguridad se llama desde un cron.darchivo. NO lo he configurado set -e, por lo que no se realiza ninguna salida en caso de error.

¿Alguna idea de por qué sucede esto?

Respuesta1

Su secuencia de comandos parece funcionar como se esperaba. La salida de dfclaramente llegó $LOG_FILEy exit 1está provocando que el script se cierre.

No sabemos qué logginghace su comando, pero AFAICT, no está destinado a escribir $LOG_FILE. Si así fuera, sería un poco tonto escribirVerifique el archivo de registro: ${LOG_FILE}allá.

Editar

Ahora que ha publicado la loggingfunción, puedo ver que utiliza una cadena aquí ( <<<).

En bash, las cadenas aquí y los documentos aquí se implementan mediante archivos temporales (en $TMPDIRo /tmpsi $TMPDIRno están definidos). Si ese fuera el sistema de archivos que estaba lleno, eso explicaría por qué loggingno generó nada.

$ sudo mount -o size=1 -t tmpfs empty /mnt/1
$ yes > /mnt/1/fill-up
yes: standard output: No space left on device
$ TMPDIR=/mnt/1 bash -c 'cat <<< test'
bash: cannot create temp file for here-document: No space left on device

En lugar de:

local now="$(date)"
cat <<< "${now} $@" | tee -a "${logfile}"

Solo usa:

printf '%(%FT%T%z)T %s\n' -1 "$*"
printf '%(%FT%T%z)T %s\n' -1 "$*" >> "$logfile"

O:

local msg
printf -v msg '%(%FT%T%z)T %s' -1 "$*"
printf '%s\n' "$msg"
printf '%s\n' "$msg" >> "$logfile"

(se supone $IFSque no está configurado o comienza con un espacio)

Eso guarda el archivo temporal, pero también evita bifurcar cualquier proceso o ejecutar cualquier comando externo (que también podría fallar bajo algunas condiciones patológicas) (y le brinda un formato de fecha más útil, siéntase libre de adaptarlo).

En términos más generales, un sistema con un sistema de archivos /tmp y /var completo es un sistema dañado y se puede esperar que muchas cosas no funcionen correctamente.

Aquí tienes suerte de tener registros. El espacio en disco para los archivos se asigna en bloques (normalmente 4K en ext4), por lo que probablemente obtuvo algunos resultados en `$LOG_FILE (ya que el último bloque se asignó antes de que se llenara el sistema de archivos).

Los scripts ejecutados por cron también tienen su stdout y stderr en un archivo temporal (luego cron intenta enviar un correo electrónico con su contenido si no están vacíos). Por lo tanto, cualquiera de los comandos podría fallar write(1, ...)o write(2, ...)fallar también (con un error ENOSPC), lo que podría provocar que se comporten mal o salgan antes de tiempo si lo consideran un error fatal.

Respuesta2

Hay una alta probabilidad de que el problema sea que

PACKING_EXITCODE=${PIPESTATUS[0]}

No hay un código de shell válido sino algo bashespecífico.

Cron llama a comandos /bin/shque difieren de bash.

Podrías dejar que tu guión comience con

#!/bin/bash

y haga que el script sea ejecutable chmod +x scriptnamepara asegurarse de que el bashcódigo específico se ejecute mediante bashel shell predeterminado y no mediante él.

información relacionada