Após a falha do tar, o script é encerrado sem tratar o erro

Após a falha do tar, o script é encerrado sem tratar o erro

Então, eu tenho um script de backup parecido com:

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

loggingé uma função para efetuar login corretamente em meu arquivo de log.

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

set_lockfile "destroy"` é uma função que remove meu arquivo de bloqueio.

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_packageé uma função para remover quaisquer arquivos temporários criados.

Eu experimentei uma falha na compactação devido a um comportamento esperado do disco cheio, como você pode imaginar para o arquivo df -h.

O interessante é o log de backup. 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

O que significa que tarfalhou, então passou pela ifcondição, de alguma forma ignorou o logging "ERROR: ...", executou o df -he morreu. pulando o resto.

De alguma forma, parece que está pulando qualquer função, mas executando os comandos.

O backup é chamado de um cron.darquivo. Eu NÃO configurei set -e, então nenhuma saída em caso de erro é feita.

Alguma idéia de por que isso está acontecendo?

Responder1

Seu script parece funcionar conforme o esperado. A saída de dfclaramente chegou $LOG_FILEe exit 1está fazendo com que o script seja encerrado.

Não sabemos o que o seu loggingcomando faz, mas AFAICT, ele não foi feito para gravar em arquivos $LOG_FILE. Se fosse, seria um pouco bobo escreverVerifique o arquivo de registro: ${LOG_FILE}lá.

Editar

Agora que você postou a loggingfunção, posso ver que ela usa uma string aqui ( <<<).

Em bash, here-strings e here-documents são implementados usando arquivos temporários (in $TMPDIRou /tmpif $TMPDIRnão está definido). Se esse fosse o sistema de arquivos que estava cheio, isso explicaria por que loggingnão gerou 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

Em vez de:

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

Apenas use:

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

Ou:

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

(assume $IFSque não está definido ou começa com espaço)

Isso salva o arquivo temporário, mas também evita a bifurcação de qualquer processo ou a execução de qualquer comando externo (que também pode falhar sob algumas condições patológicas) (e fornece um formato de data mais útil, fique à vontade para adaptar).

De forma mais geral, um sistema com um sistema de arquivos /tmp e /var completo é um sistema danificado, você pode esperar que muitas coisas não funcionem corretamente.

Aqui, você tem sorte de ter registros. O espaço em disco para arquivos é alocado em blocos (normalmente 4K no ext4), e é provavelmente por isso que você obteve alguma saída em `$LOG_FILE (já que o último bloco foi alocado antes do sistema de arquivos ficar cheio).

Os scripts executados pelo cron também têm stdout e stderr em um arquivo temporário (então o cron tenta enviar um email com seu conteúdo se não estiverem vazios). Portanto, qualquer um dos comandos também pode write(1, ...)falhar write(2, ...)(com erro ENOSPC), o que pode fazer com que eles se comportem mal ou saiam mais cedo se considerarem um erro fatal.

Responder2

Há uma grande probabilidade de que o problema seja esse

PACKING_EXITCODE=${PIPESTATUS[0]}

não há código de shell válido, mas algo específico bash.

Cron chama comandos /bin/shdiferentes do bash.

Você poderia deixar seu script começar com

#!/bin/bash

e torne o script executável usando chmod +x scriptnamepara garantir que o bashcódigo específico seja executado bashe não pelo shell padrão.

informação relacionada