
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
logging
ist 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_package
ist 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, tar
es ist fehlgeschlagen, dann hat es die Bedingung durchlaufen if
, irgendwie das übersprungen logging "ERROR: ..."
, das ausgeführt df -h
und 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.d
Datei 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 df
hat es eindeutig bis geschafft $LOG_FILE
und exit 1
führt dazu, dass das Skript beendet wird.
Wir wissen nicht, was Ihr logging
Befehl 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 logging
Funktion gepostet haben, kann ich sehen, dass sie einen Here-String ( <<<
) verwendet.
In bash
werden Here-Strings und Here-Dokumente mithilfe von temporären Dateien implementiert (in $TMPDIR
oder /tmp
wenn $TMPDIR
nicht definiert ist). Wenn das Dateisystem voll war, würde das erklären, warum logging
nichts 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, $IFS
dass 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 bash
Spezifisches.
Cron ruft Befehle mit auf, /bin/sh
die sich von unterscheiden bash
.
Sie könnten Ihr Skript mit Folgendem beginnen lassen:
#!/bin/bash
und machen Sie das Skript ausführbar, chmod +x scriptname
um sicherzustellen, dass der spezifische Code von und nicht von der Standard-Shell bash
ausgeführt wird .bash