Bash-Scripting: leere und veraltete Dateien finden und per Mail verschicken

In einer Tagessicherung landen in der Regel Dateien und Verzeichnisse, die zu einem Package (TAR, ZIP oder ähnliches) zusammengefasst werden. Bei einer solchen Tagessicherung kann es zu unerwarteten Fehlern kommen. Treten Fehler beim packen der Daten auf, findet man eine leere Package-Datei im Sicherungsordner. Und noch viel schlimmer: die Tagessicherung ist inaktiv, die Tagessicherung ist also nicht vom Vortag, sondern veraltet.

Beide Fälle sollten natürlich vermieden werden, um im Worst Case Szenario auf ein aktuelles und vollständiges Backup zurückgreifen zu können. Wir stellen daher ein Linux Bash Script vor, welches folgende Fehlerbehandlung durchführt:

  • Leere Dateien finden
  • Veraltete Dateien finden
  • E-Mail mit betroffenen Dateien verschicken

 Für die ersten beiden Anforderungen können wir das Tool find verwenden.

# Finde Dateien älter als zwei Tage
find /path/ -type f -mtime +2

# Finde leere Dateien
find /path/ -type f -empty

Mit -type f suchen wir nur nach Dateien und schließen Verzeichnisse aus. Mit -mtime (aka Modified Time) suchen wir nach der letzten Aktualisierung einer Datei. Mit +2 sagen wir älter als zwei Tage, da es nach "n mal 24 Stunden" berechnet wird. In der Manpage steht dazu folgendes: "If no units are specified, this primary evaluates to true if the difference between the file last modification time and the time find was started, rounded up to the next full 24-hour period, is n 24-hour periods.". Noch einfacher ist es mit leeren Dateien, die mit -empty gefunden werden.

Das Script

Natürlich wollen wir die Logik wiederverwenden und strukturieren unser Script durch Verwenden einer functions.sh, in welche wir zwei Methoden mit einem ordentlichen Exit Code implementieren. 

# functions.sh
#
# Find old files and print them out
# Exit codes:
# 0 = run successful
# 100 = wrong usage
#
findOldFiles()
{
if [ "$#" -ne 2 ]; then
echo "wrong parameters"
error "use findOldFiles /path/ numberOfDays "
error "example: findOldFiles /tmp/ 2 "
exit 100;
fi

INPUT_PATH=$1
INPUT_DAYS=$2
RESULT=$(find ${INPUT_PATH} -type f -mtime +${INPUT_DAYS})

if [ "${RESULT}" != "" ]
then
for item in ${RESULT}; do echo ${item}; done
fi

exit 0
}

# Find empty files and print them out
#
# Exit codes:
# 0 = run successful
# 100 = wrong usage
#
findEmptyFiles()
{
if [ "$#" -ne 1 ]; then
echo "Wrong parameters"
echo "use: findEmptyFiles /path/ "
exit 100;
fi

INPUT_PATH=$1
INPUT_DAYS=$2
RESULT=$(find ${INPUT_PATH} -type f -empty)

if [ "${RESULT}" != "" ]
then
for item in ${RESULT}; do echo ${item}; done
fi

exit 0
}

Warum das Auslagern in Methoden. Zum einen haben wir eine Fehlerbehandlung und zum anderen eine angepasst Ausgabe, die wir später für das Versenden der Mail benötigen. Wir wollen nur Versenden, wenn Dateien gefunden wurden.

So sieht das fertige Script aus, welches die Methoden aus der functions.sh verwendet:

#!/bin/bash
#
# Find empty and old backups
#

# INCLUDES
source $(dirname $0)/functions.sh

# VARIABLES
BACKUP_DIR=/path/to/backups
MAX_DAYS=2
MAILTO=mschmidt@pc-erfahrung.de

# old files
OLD_FILES=$(findOldFiles ${BACKUP_DIR} ${MAX_DAYS})
if [ $? = 0 ] && [ "${OLD_FILES}" != "" ]; then
for item in $OLD_FILES; do echo "$(date -r $item) $item"; done | mutt -s "CRITICAL - $HOSTNAME: veraltete Sicherung" ${MAILTO}
fi

# empty files
EMPTY_FILES=$(findEmptyFiles ${BACKUP_DIR})
if [ $? = 0 ] && [ "${EMPTY_FILES}" != "" ]; then
for item in $EMPTY_FILES; do echo $item; done | mutt -s "CRITICAL - $HOSTNAME: leere Sicherung" ${MAILTO}
fi

Nachdem wir unsere Parameter in Variablen definiert haben, setzen wir einmal findOldFiles und findEmptyFiles ein. Nur wenn find Dateien findet, gehen wir alle Suchtreffer durch und verschicken diese mit mutt.

Der Praxis-Test

Wir nehmen das /var/log/ Verzeichnis. Die Orange markierten Dateien sind entweder zu alt (also älter als 1. März) oder leer (Dateigröße = 0).

# ls -lsh /var/log/
total 1.8M
   0 -rw-r--r-- 1 root root    0 Mar  1 03:41 alternatives.log
 16K -rw-r--r-- 1 root root  13K Dec 11 22:05 alternatives.log.1
4.0K drwxr-xr-x 2 root root 4.0K Mar  1 03:41 apt
4.0K -rw-r----- 1 root adm   881 Mar  1 05:17 auth.log
 24K -rw-r----- 1 root adm   18K Mar  1 03:41 auth.log.1
   0 -rw-rw---- 1 root utmp    0 Mar  1 03:41 btmp
4.0K -rw------- 1 root utmp 3.4K Dec 11 22:51 btmp.1
4.0K -rw-r----- 1 root adm  3.4K Mar  1 05:41 daemon.log
148K -rw-r----- 1 root adm  144K Mar  1 03:36 daemon.log.1
   0 -rw-r----- 1 root adm     0 Mar  1 03:41 debug
 72K -rw-r----- 1 root adm   68K Mar  1 03:36 debug.1
4.0K -rw-r----- 1 root adm    31 Apr 25  2017 dmesg
   0 -rw-r--r-- 1 root root    0 Mar  1 03:41 dpkg.log
220K -rw-r--r-- 1 root root 216K Dec 11 22:07 dpkg.log.1
8.0K -rw-r--r-- 1 root root  32K Dec 11 22:07 faillog
4.0K drwxr-xr-x 2 root root 4.0K Apr 25  2017 fsck
4.0K drwxr-xr-x 3 root root 4.0K Apr 25  2017 installer

   0 -rw-r----- 1 root adm     0 Mar  1 03:41 kern.log
372K -rw-r----- 1 root adm  365K Mar  1 03:36 kern.log.1
 12K -rw-rw-r-- 1 root utmp 286K Mar  1 03:45 lastlog
4.0K -rw-r----- 1 root adm   404 Mar  1 03:45 messages
300K -rw-r----- 1 root adm  299K Mar  1 03:41 messages.1
8.0K -rw-r----- 1 root adm  4.6K Mar  1 05:41 syslog
524K -rw-r----- 1 root adm  518K Mar  1 03:41 syslog.1
4.0K -rw-rw-r-- 1 root utmp  384 Mar  1 03:45 wtmp
 28K -rw-rw-r-- 1 root utmp  21K Mar  1 03:36 wtmp.1

Das Ergebnis ist wie folgt. Bei den veralteten Dateien wurde noch das Datum ergänzt (siehe date -r):

+++++++++
OLD FILES
+++++++++
Tue Apr 25 02:30:21 CDT 2017 /var/log/fsck/checkfs
Tue Apr 25 02:30:21 CDT 2017 /var/log/fsck/checkroot
Mon Dec 11 22:51:16 CST 2017 /var/log/btmp.1
Mon Dec 11 22:05:54 CST 2017 /var/log/alternatives.log.1
Mon Dec 11 22:07:17 CST 2017 /var/log/dpkg.log.1
Mon Dec 11 22:07:17 CST 2017 /var/log/faillog
Tue Apr 25 02:30:21 CDT 2017 /var/log/dmesg
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/cdebconf/questions.dat
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/cdebconf/templates.dat
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/lsb-release
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/status
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/hardware-summary
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/partman
Tue Apr 25 02:37:23 CDT 2017 /var/log/installer/syslog
Mon Dec 11 22:07:17 CST 2017 /var/log/apt/history.log.1.gz
Mon Dec 11 22:07:17 CST 2017 /var/log/apt/term.log.1.gz
+++++++++++
EMPTY FILES
+++++++++++
/var/log/btmp
/var/log/kern.log
/var/log/dpkg.log
/var/log/alternatives.log
/var/log/debug
/var/log/apt/history.log
/var/log/apt/term.log

Bei Rückfragen zu diesem Script könnt Ihr Euch gerne im Forum melden.