kai 'oswald' seidler (blog)
24. Juni

rsync und das Rätsel um die Exclude-Option

24. Juni 2008, 20:53 Uhr, Software

newrsynclogo.jpgMein absoluter Backup-Liebling ist ja rsync. Sicherlich nicht perfekt, aber für 99.9% der Fälle ist es ein wunderbares und einfaches Werkzeug zum bequemen Sichern von Systemen. Okay, das Logo (das da rechts) ist nicht von dieser Welt. “Form follows function” in die Unendlichkeit gesteigert.

Ansonsten, schöne Software, einfacher geht es eigentlich kaum noch. Bei der Exclude-Option allerdings, die es ermöglicht Dateien oder Verzeichnisse vom Backup auszuschießen, bekommt man gerne mal graue Haare.

Meist beziehen sich die Probleme der Rsync-Einsteiger auf die Anwendung von mehreren Exclude-Optionen um mehrere Ausschluss-Parameter anzugeben. Ein triviales Problem, das schnell zu lösen ist.

Eng mit diesem Problem verbunden, ist aber auch noch ein weiteres Problem, das viele Benutzer zusätzlich frustriert: Manchmal sieht es nämlich so aus, als ob die Exclude-Option gar nicht richtig funktionieren würde.

Ich nenne dieses Problem gerne das absolute Relativpfade-Problem. In rsync(1) wird dieses “Problem” zwar auch erwähnt, aber nur ganz versteckt beantwortet (mehr dazu ganz unten).

Bevor ich jetzt versuche das Problem mit vielen Worten zu beschreiben, male ich es einfach mal mit einem Beispiel auf.

Das Szenario

Stellen wir uns vor, auf dem zu kopierenden Server (im Folgenden straylight genannt) gibt es unter /home/oswald/test diese Datei-Hierarchie:

straylight> find /home/oswald/test -ls
drwxr-xr-x 3 oswald  4096 Jun 25 10:05 /home/oswald/test
drwxr-xr-x 2 oswald  4096 Jun 25 10:05 /home/oswald/test/haha
-rw-r--r-- 1 oswald     0 Jun 25 10:05 /home/oswald/test/haha/hoho
-rw-r--r-- 1 oswald     0 Jun 25 10:05 /home/oswald/test/huhu

Dieses Verzeichnis soll kopiert werden, jedoch ohne das Unterverzeichnis haha und dessen Inhalte.

Um das Problem noch ein wenig komplizierter werden zu lassen, gibt es auch noch zwei Varianten in denen es (unterschiedlich) auftritt. Schauen wir uns zunächst die eine Variante an.

Variante 1: Ohne trailing slash

Zunächst nehmen wir einen ganz normaler rsync-Befehl ohne Exclude-Regel und kopieren die komplette Hierarchie auf einen zweiten Rechner (hier freeside genannt):

freeside> rsync -avz -e ssh --delete
oswald@straylight:/home/oswald/test /tmp/hihi
receiving file list ... done
created directory /tmp/hihi
test/
test/haha/
test/haha/hoho
test/huhu

sent 56 bytes  received 174 bytes  153.33 bytes/sec
total size is 0  speedup is 0.00

Da hier die Quellenangabe nicht auf ein Slash endet, wird auch das Verzeichnis test selbst kopiert:

freeside> find /tmp/hihi -ls
drwxr-x--- 3 oswald users   72 Jun 25 10:37 /tmp/hihi
drwxr-xr-x 3 oswald users   96 Jun 25 10:05 /tmp/hihi/test
drwxr-xr-x 2 oswald users   72 Jun 25 10:05 /tmp/hihi/test/haha
-rw-r--r-- 1 oswald users    0 Jun 25 10:05 /tmp/hihi/test/haha/hoho
-rw-r--r-- 1 oswald users    0 Jun 25 10:05 /tmp/hihi/test/huhu

Soweit kein Problem. Um die Ausgangslage wiederherzustellen, löschen wir nun das kopierte Verzeichnis wieder.

freeside> rm -rf /tmp/hihi

Jetzt ein rsync mit Exclude-Regel: Das Verzeichnis haha (samt Inhalt hoho) soll nicht kopiert werden. Bei der Exclude-Option geben wir also /home/oswald/test/haha an.

freeside> rsync -avz -e ssh --exclude=/home/oswald/test/haha --delete
oswald@straylight:/home/oswald/test /tmp/hihi
receiving file list ... done
created directory /tmp/hihi
test/
test/haha/
test/haha/hoho
test/huhu

sent 82 bytes  received 174 bytes  170.67 bytes/sec
total size is 0  speedup is 0.00

An der Ausgabe des Rsync-Befehls sehen wir schon, dass das haha-Verzeichnit trotzdem kopiert wurde. Was lief falsch?

Zunächst löschen wir das kopierte Verzeichnis wieder.

freeside> rm -rf /tmp/hihi

Um das Ganze jetzt abzukürzen, verwenden wir hier gleich die funktionierende, richtige Version und geben bei der Exclude-Option /test/haha an:

freeside> rsync -avz -e ssh --exclude=/test/haha --delete
oswald@straylight:/home/oswald/test /tmp/hihi
receiving file list ... done
created directory /tmp/hihi
test/
test/huhu

sent 50 bytes  received 104 bytes  102.67 bytes/sec
total size is 0  speedup is 0.00

Jetzt hat es geklappt. Das haha-Verzeichnis wurde nicht kopiert. Woran liegt’s? Die Pfadangabe bei der Exclude-Option darf nicht absolut, sondern muss quasi-relativ zum Ausgangsverzeichnis der Quellenangabe sein. Wenn ich /home/oswald/test kopiere, dann ist /test/haha die richtige Referenz auf das Verzeichnis /home/oswald/test/haha.

Und damit kommen wir zur 2. Variante dieses Problems.

Zunächst löschen wir das kopierte Verzeichnis wieder.

freeside> rm -rf /tmp/hihi

Variante 2: Mit trailing slash

Für Unix-Befehle ist es immer ein großer Unterschied, ob man Verzeichnisse mit oder ohne einem trailing slash adressiert. Um den Unterschied in diesem Fall zu zeigen, rufen wir den Ausgangs-Rsync-Befehl nochmals auf. Nur dieses Mal mit einem angehängten Slash.

freeside> rsync -avz -e ssh --delete
oswald@straylight:/home/oswald/test/ /tmp/hihi
receiving file list ... done
created directory /tmp/hihi
./
haha/
haha/hoho
huhu

sent 56 bytes  received 169 bytes  150.00 bytes/sec
total size is 0  speedup is 0.00

Da hier die Quellenangabe nun mit einem Slash endet, wird der Inhalt von test kopiert und nicht das Verzeichnis test selbst:

freeside> find /tmp/hihi -ls
693847 0 drwxr-xr-x 3 oswald users   96 Jun 25 10:05 /tmp/hihi
693925 0 drwxr-xr-x 2 oswald users   72 Jun 25 10:05 /tmp/hihi/haha
693988 0 -rw-r--r-- 1 oswald users    0 Jun 25 10:05 /tmp/hihi/haha/hoho
693989 0 -rw-r--r-- 1 oswald users    0 Jun 25 10:05 /tmp/hihi/huhu

Zunächst löschen wir das kopierte Verzeichnis erneut.

freeside> rm -rf /tmp/hihi

Um in diesem Fall das Verzeichnis /home/oswald/test/haha vom Kopieren auszuschiessen, muss bei der Exclude-Option /haha angegeben werden:

freeside> rsync -avz -e ssh --exclude=/haha --delete
oswald@straylight:/home/oswald/test/ /tmp/hihi
receiving file list ... done
created directory /tmp/hihi
./
huhu

sent 45 bytes  received 99 bytes  96.00 bytes/sec
total size is 0  speedup is 0.00

Wunderbar, haha und sein Inhalt hoho wurden nicht kopiert.

Die Erklärung

Eigentlich ist es ganz einfach: Die Angabe bei der Exclude-Option ist ein Pattern und kein Verzeichnis. Und dieses Pattern wird auf das, was da kopiert wird, angewendet. Beim Kopieren wird nicht der absolute sondern nur der relative Pfad kopiert und eben diesen Pfad muss das Pattern matchen. Der Slash am Anfang von /haha hat nichts mit dem Root-Verzeichnis eines Dateisystems zu tun und bezieht sich nur auf den kopierenden Pfad.

Im Manual rsync(1) wird dazu der Begriff ‘root of the transfer’ eingeführt und so erkärt:

If the pattern starts with a / then it is anchored to a particular spot in the hierarchy of files, otherwise it is matched against the end of the pathname. This is similar to a leading ^ in regular expressions. Thus ‘/foo’ would match a file named ‘foo’ at either the ‘root of the transfer’ (for a global rule) or in the merge-file’s directory (for a per-directory rule).

Kurzum: Die Exclude-Option bezieht sich auf das ‘root of the transfer’.

Lässt man das Slash am Anfang weg und schreibt also anstelle von /haha nun haha, dann werden komplett unabhägig vom Pfad alle Verzeichnisse und Dateien, die genau haha heißen, ignoriert.

Zusätzlich kann man dann natürlich auch noch die üblichen Unix-Shell-Wildcards * und ? in diesem Pattern verwenden. Aber das ist eine andere Geschichte und die ist auch wieder ganz trivial.

13 Kommentare


Maex
25.6.08 12:11

Sehr guter Artikel und sehr schön erklärt!

Ich habe jedoch einige Anmerkungen :-)

1) Ich finde es wichtig die option -H zu verwenden, damit hardlinks auch hardlinks bleiben. Im Falle eines Restaurierens der Daten könnte das sonst ätzend werden. Ich verstehe nicht, warum das bei “-a” nicht ohnehin enthalten ist :-(

2) Für Backups mit der Option auf zeitlich längere “error recovery” verwende ich ein einem Skript TSTAMP=`date +’%F’` und dann die Optionen --backup --backup-dir=daily/”${TSTAMP}”. Auf diese Weise hat man einen Baum, der aktuell ist, sowie ein Unterverzeichnis “daily” in dem nach Tagen getrennt alle Änderungen zu jeweiligen Vortrag enthalten sind. Damit erreicht man dann quasi inkrementelle Backups auf Ebene 1 – obwohl … eher eine Mischung aus vollständig, inkrementell und differentiell :-)

3) Auf meinem Backup-Server will ich Daten länger halten als auf meinem Original-Server. Dies betrifft z.B. manche Logfiles oder eMails. Zu diesem Zweck verschiebe ich die Daten auf dem Backup-Server nach einen rsync jeweils in Unterverzeichnisse namens “archives”. Um zu verhindern, dass der rsync mit --delete diese Daten löscht, muß man diese Verzeichnisse und deren Inhalte schützen. Dazu verwende ich die Option --filter=’protect archives/*’. Vor dem “archives” steht kein Slash, damit das überall im Verzeichnisbaum funktioniert. Der “*” ist in diesem Fall für das Matching nötig.



Oswald
25.6.08 13:38

Cool! Danke für die Tipps, Maex! :)



blacktux
9.1.09 15:31

Sehr feiner Artikel,

endlich mal Licht ins Dunkel gebracht. :-)

Grüsse aus Hamburg



pir187
2.2.09 17:44

Hi Oswald,

danke für den Artikel, hat mir bzgl. Excludes auf die Sprünge geholfen. Vielleicht “sehen” wir uns mal wieder im AF-Forum – hab mir gestern erst die aktuelle Version 1.7 für Linux geholt :)

Viele Grüße, Kay aka pir187



Frank
13.2.09 23:07

Kurze Frage zu den Excludes. Gibt’s denn auch eine Möglichkeit damit gleichnamige Verzeichnisse in einem Baum auf einmal auszuschliessen? Beispiel: In einem Baum gibt’s verzeichnisse verz1 bis verz5 – jedes dieser 5 Verzeichnisse enthält ein Unterverzeichnis test inklusive daten/baum darunter. Gibt’s da ne Möglichkeit alle Verzeichnisse Namens “test” inkl. Daten und Verzeichnissen darunter auszuschließen?



Oswald
15.2.09 13:39

Hallo Frank!

Wie oben schon geschrieben, ist die Angabe bei Exclude ein Pattern und damit ist Dein Fall eigentlich ganz einfach zu lösen. Zum Beispiel --exclude "lala/verz*/test".

Liebe Grüße!



M. Junker
13.4.09 20:24

Yesssssssss, big thx !!!!!!!

2 Stunden selbst rumgewurschtelt und deine Erklärung
zu –exclude und dem relativen Pfad war es.

YMMD

Jetzt bin ich reichlich froh und habe ich keine Lust mehr.
Werde wohl was fernschauen. rsync macht es ja jetzt wie ich es will :=)))))



Harald
10.5.09 09:26

thxalot.



Harald
10.5.09 09:28

oops, nochwas vergessen.

Hallo Oswald,

schon mal dirvish ausprobiert? das ganze ergänzt rsync zum kompletten Archivieringsprogramm. http://www.dirvish.org.

Grüße
Harald



Nils
4.8.09 00:38

Du hast mir mit diesem Artikel gerade wirklich sehr geholfen.
Vielen Dank :)



normann
13.8.09 09:11

danke



resuba
6.10.09 09:01

Hey, erstmal Danke, ist eine gute Erklärung (läuft bei mir aber schon seit Jahren so).

Jetzt zu meinem Problem:

Server 1

es gibt einen Ordner /x/mp3
dort befinden sich meine gesicherten LPs und CDs
ein Teil derer laufen im Zufallsgenerator als Hintergrundmusik
/X/mp3/play
/X/mp3/album ist nicht in der Playlist

Server 2 hat eine andere Struktur
dort gibt es auch /x/mp3/play
der Inhalt ist identisch, nur in Unterverzeichnissen, also

/x/mp3/play/mp1
/x/mp3/play/mp2
/x/mp3/play/mp3

Nun das Problem
wie schaffe ich folgendes
root@server1:rsync [OPTIONS] –exclude=album /x/mp3/play/mp1 /x/mp3/play/mp2 /x/mp3/play/mp3 root@server2:/x/mp3/play

lg. Rene



Gerhard Lehnhoff
29.12.09 13:06

Endlich habe ich es kapiert und endlich funktioniert es. Danke.


Leave a Reply

 

oswaldism.deblog.oswaldism.demicroblog.oswaldism.degallery.oswaldism.de