Nach einem Tar-Fehler wird das Skript beendet, ohne den Fehler zu behandeln.

Nach einem Tar-Fehler wird das Skript beendet, ohne den Fehler zu behandeln.

Ich habe also ein Backup-Skript, das so aussieht:

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

loggingist eine Funktion um mich ordnungsgemäß in meine Logdatei einzuloggen.

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

„set_lockfile ‚destroy‘“ ist eine Funktion, die meine Sperrdatei entfernt.

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_packageist eine Funktion zum Entfernen aller erstellten temporären Dateien.

Bei mir ist das Packen aufgrund einer vollen Festplatte fehlgeschlagen. Das ist das erwartete Verhalten, wie Sie sich denken können df -h.

Interessant ist das Backup-Protokoll. Darin steht:

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

Das heißt, tares ist fehlgeschlagen, dann hat es die Bedingung durchlaufen if, irgendwie das übersprungen logging "ERROR: ...", das ausgeführt df -hund ist beendet. Der Rest wurde übersprungen.

Sieht irgendwie so aus, als würde jede Funktion übersprungen, aber die Befehle ausgeführt.

Das Backup wird aus einer cron.dDatei aufgerufen. Ich habe es NICHT gesetzt set -e, daher erfolgt kein Beenden im Fehlerfall.

Irgendwelche Ideen, warum das passiert?

Antwort1

Ihr Skript scheint wie erwartet zu funktionieren. Die Ausgabe von dfhat es eindeutig bis geschafft $LOG_FILEund exit 1führt dazu, dass das Skript beendet wird.

Wir wissen nicht, was Ihr loggingBefehl tut, aber soweit ich weiß, ist er nicht dafür gedacht, in zu schreiben $LOG_FILE. Wenn das der Fall wäre, wäre es ein bisschen albern, zu schreibenÜberprüfen Sie die Protokolldatei: ${LOG_FILE}Dort.

Bearbeiten

Nachdem Sie die loggingFunktion gepostet haben, kann ich sehen, dass sie einen Here-String ( <<<) verwendet.

In bashwerden Here-Strings und Here-Dokumente mithilfe von temporären Dateien implementiert (in $TMPDIRoder /tmpwenn $TMPDIRnicht definiert ist). Wenn das Dateisystem voll war, würde das erklären, warum loggingnichts ausgegeben wurde.

$ 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

Anstatt:

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

Benutz einfach:

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

Oder:

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

(nimmt an, $IFSdass es nicht gesetzt ist oder mit einem Leerzeichen beginnt)

Dadurch wird die temporäre Datei gespeichert, aber auch das Aufspalten von Prozessen oder Ausführen externer Befehle (was unter pathologischen Bedingungen ebenfalls fehlschlagen könnte) wird vermieden (und Sie erhalten ein nützlicheres Datumsformat, das Sie gerne anpassen können).

Allgemeiner gesagt ist ein System mit einem vollständigen /tmp- und /var-Dateisystem ein beeinträchtigtes System. Sie können davon ausgehen, dass viele Dinge nicht richtig funktionieren.

Hier haben Sie Glück, dass Sie überhaupt Protokolle haben. Der Speicherplatz für Dateien wird in Blöcken zugewiesen (normalerweise 4 KB auf ext4), was wahrscheinlich der Grund ist, warum Sie eine Ausgabe in `$LOG_FILE erhalten haben (da der letzte Block zugewiesen wurde, bevor das Dateisystem voll war).

Von cron ausgeführte Skripte haben ihre stdout- und stderr-Ausgabe ebenfalls in einer temporären Datei (dann versucht cron, eine E-Mail mit ihrem Inhalt zu senden, wenn sie nicht leer sind). Daher könnte jeder der Befehle auch ihre haben write(1, ...)oder write(2, ...)fehlschlagen (mit ENOSPC-Fehler), was zu Fehlverhalten oder vorzeitigem Beenden führen könnte, wenn sie es als schwerwiegenden Fehler betrachten.

Antwort2

Es besteht eine hohe Wahrscheinlichkeit, dass das Problem darin besteht,

PACKING_EXITCODE=${PIPESTATUS[0]}

ist kein gültiger Shell-Code, sondern etwas bashSpezifisches.

Cron ruft Befehle mit auf, /bin/shdie sich von unterscheiden bash.

Sie könnten Ihr Skript mit Folgendem beginnen lassen:

#!/bin/bash

und machen Sie das Skript ausführbar, chmod +x scriptnameum sicherzustellen, dass der spezifische Code von und nicht von der Standard-Shell bashausgeführt wird .bash

verwandte Informationen