PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Shellscript: Backup Script mit merkwürdigen Verhalten



bema
02-06-2007, 23:10
Hallo,

ich habe mir ein kleines Backup Skript geschrieben mit dem ich zwei Verzeichnisse rekursiv auf Inhalt überprüfe. Existiert in dem Zielverzeichnis eine Datei nicht, welche aber im Quellverzeichnis existiert, wird sie im Zielverzeichnis angelegt. Das selbe gilt für Unterverzeichnisse und deren Inhalt.

Nun zu dem Problem: Nachdem ein Unterverzeichnis gefunden wurde, wird es ggf. angelegt. Danach wird in das Verzeichnis gewechselt und alle darin befindlichen Dateien abgearbeitet. Danach wird die Funktion welche das Unterverzeichnis bearbeitet hat verlassen und die aufrufende Funktion arbeitet das aktuelle Verzeichnis weiter ab.
Nur irgendwie steht dann plötzlich in der Variable welche sich das aktuelle Verzeichnis merkt, dass Verzeichnis vom letzten rekursiven Aufruf. Und das obwohl ich den Wert der Variable nicht ändere.
Soll heißen: Sobald ein Unterverzeichnis abgearbeitet wurde, können alle (alphabetisch) nach dem Unterverzeichnis folgenden Dateien nicht mehr abgearbeitet werden, da das Skript meint, diese würden im bereits abgearbeiteten Unterverzeichnis liegen.

Ich kann den Fehler einfach nicht finden und würde mich freuen wenn ihr da mal drüber schaut. Das Skript ist so ziemlich mein erstes Shell-Script und vielleicht habe ich ja einen kleinen aber entscheidenden Fehler gemacht.



#!/bin/sh

################################################## ########

function Check()
{
SOURCE=${1}
BACKUP=${2}

echo "Aktuelles Verzeichnis: ${SOURCE}"
# Solange ls Ergebnis liefert
for i in `ls ${SOURCE}`
do
echo "Pruefe ${SOURCE}/$i"
# Wenn es ein Verzeichnis ist
if [ -d "${SOURCE}/${i}" ]
then
# Wenn das Verzeichnis noch nicht existiert
if [ ! -d "${BACKUP}/${i}" ]
then
# Lege das Verzeichnis an
mkdir ${BACKUP}/${i}
echo "Verzeichnis ${BACKUP}/${i} wurde erstellt"
fi
# Pruefe Inhalte des Verzeichnis
Check ${SOURCE}/${i} ${BACKUP}/${i}
# Ansonsten ist es eine Datei
else
# Wenn die Datei neuer ist
if [ "${SOURCE}/${i}" -nt "${BACKUP}/${i}" ]
then
# Kopiere sie
cp ${SOURCE}/${i} ${BACKUP}/${i}
echo "${SOURCE}/${i} wurde gesichert"
fi
fi

done
echo "Verzeichnis wird verlassen: ${SOURCE}"
}

################################################## ########

SOURCE_DIR=${1}
BACKUP_DIR=${2}

################################################## ########

if [ ! ${#} -eq 2 ]
then
echo "Usage: ${0} <source_dir> <backup_dir>"
exit -1
fi

if [ ! -d ${SOURCE_DIR} ]
then
echo "Der erste Parameter muss ein Verzeichnis sein!"
exit -1
fi

if [ ! -d ${BACKUP_DIR} ]
then
echo "Der zweite Parameter muss ein Verzeichnis sein!"
exit -1
fi

################################################## #######

Check ${SOURCE_DIR} ${BACKUP_DIR}



Vielen Dank! :)

bema
02-06-2007, 23:15
Ich habe jetzt eine Übergangslösung implementiert welche einfach vor dem Aufruf von Check() das aktuelle Verzeichnis (aus SOURCE und BACKUP) in einer Variable speichert und nach dem Funktionsaufruf zurück schreibt.

Aber wieso ändert sich der Wert überhaupt erst??


Nachtrag: Leider funktioniert diese Lösung nicht wirklich. Sobald sich in dem Unterverzeichnis ein weiteres Unterverzeichnis befindet, wird meine Lösung außer Kraft gesetzt. Das versteht ich nicht :(

zst
04-06-2007, 23:04
Hallo bema,

ich denke, diese Zeile macht Dir die Probleme:

Check ${SOURCE}/${i} ${BACKUP}/${i}
Du rufst hier die Funktion in der Funktion auf.

Übrigens: Wenn ein Verzeichnis noch nicht existiert, könntest Du auf das Anlegen und das einzelne Kopieren der darin befindlichen Dateien verzichten, wenn Du cp -r ... benutzt.

Viel Erfolg!
Gruss zst

bema
04-06-2007, 23:30
Danke für den Tipp. Wenn das Verzeichnis noch nicht existiert, es einfach samt Inhalt zu kopieren ist natürlich intelligenter.

Aber wieso darf ich in einer Funktion nicht die Funktion aufrufen? Ist das bei Shell-Scripts nicht erlaubt? Gibt es noch eine andere Möglichkeit? Sicherlich könnte ich versuchen eine iterative Lösung zu finden, aber rekursives Abarbeiten ist beim Durchlaufen von Verzeichnissen deutlich besser finde ich.

jan61
04-06-2007, 23:53
...
Aber wieso darf ich in einer Funktion nicht die Funktion aufrufen? Ist das bei Shell-Scripts nicht erlaubt? Gibt es noch eine andere Möglichkeit? Sicherlich könnte ich versuchen eine iterative Lösung zu finden, aber rekursives Abarbeiten ist beim Durchlaufen von Verzeichnissen deutlich besser finde ich.

Doch, natürlich ist Rekursion auch in der bash möglich. Deine Idee ist also erstmal gar nicht so schlecht - ABER: Du hast ein Problem mit den Variablen SOURCE und BACKUP, das sind nämlich globale Variablen. Und da liegt der Hase im Pfeffer begraben. Nachdem der 1. rekursive Aufruf von Check in Deiner Schleife zurückkommt, sitzen die Variablen SOURCE und BACKUP auf den in der untersten Ebene zuletzt gesetzten Werten - nicht mehr auf denjenigen, die Du am Beginn der Funktion zugewiesen hast.

Was Du suchst, ist
local. Damit deklarierst Du eine lokale Variable.

Jan

P.S.: Schau Dir mal rsync an - aber dann ist der ganze Spaß mit der Bash-Programmiererei hin ;-)

bema
05-06-2007, 09:56
Vielen Dank! Das war das Schlüsselwort welches mir gefehlt hat :-) Jetzt funktioniert das Skript super!