tar --exclude schließt nicht aus. Warum?

71

Ich habe diese sehr einfache Linie in einem Bash - Skript , das erfolgreich ausführt (dh die Erzeugung _data.tarDatei), mit der Ausnahme , dass es nicht der Fall ist , die Unterverzeichnisse ausschließen es gesagt wird über die ausschließen --excludeOption:

/bin/tar -cf /home/_data.tar  --exclude='/data/sub1/*'  --exclude='/data/sub2/*' --exclude='/data/sub3/*'  --exclude='/data/sub4/*'  --exclude='/data/sub5/*'  /data

Stattdessen wird eine _data.tarDatei erstellt, die alles unter / data enthält, einschließlich der Dateien in den Unterverzeichnissen, die ich ausschließen wollte.

Irgendeine Idee warum? und wie kann man das beheben?

Update Ich habe meine Beobachtungen basierend auf dem Link implementiert, der in der ersten Antwort unten angegeben ist (oberste Ebene zuerst, kein Leerzeichen nach dem letzten Ausschluss):

/bin/tar -cf /home/_data.tar  /data  --exclude='/data/sub1/*'  --exclude='/data/sub2/*'  --exclude='/data/sub3/*'  --exclude='/data/sub4/*'  --exclude='/data/sub5/*'

Aber das hat nicht geholfen. Alle "ausgeschlossenen" Unterverzeichnisse sind in der resultierenden _data.tarDatei vorhanden.

Das ist rätselhaft. Egal, ob dies ein Fehler in aktuellem tar (GNU tar 1.23, unter CentOS 6.2, Linux 2.6.32) oder eine "extreme Empfindlichkeit" von tar gegenüber Leerzeichen und anderen leicht zu übersehenden Tippfehlern ist, ich halte dies für einen Fehler. Zur Zeit.

Das ist schrecklich : Ich habe die unten vorgeschlagene Einsicht ausprobiert (kein Nachstellen /*) und es funktioniert immer noch nicht im Produktionsskript:

/bin/tar -cf /home/_data.tar  /data  --exclude='/data/sub1'  --exclude='/data/sub2'  --exclude='/data/sub3'  --exclude='/data/sub4'

Ich sehe keinen Unterschied zwischen dem, was ich versucht habe und dem, was @ Richard Perrin versucht hat, mit Ausnahme der Anführungszeichen und 2 Leerzeichen anstelle von 1. Ich werde dies versuchen (muss warten, bis das nächtliche Skript als zu sicherndes Verzeichnis ausgeführt wird) up is huge) und melde dich zurück.

/bin/tar -cf /home/_data.tar  /data --exclude=/data/sub1 --exclude=/data/sub2 --exclude=/data/sub3 --exclude=/data/sub4

Ich beginne zu denken, dass all diese tar --excludeEmpfindlichkeiten nicht Teer sind, sondern etwas in meiner Umgebung, aber was könnte das dann sein?

Es funktionierte! Die letzte --excludegetestete Variante (keine einfachen Anführungszeichen und ein Leerzeichen anstelle eines doppelten Leerzeichens zwischen den s) funktioniert. Seltsam, aber akzeptierend.

Nicht zu fassen! Es stellt sich heraus, dass eine ältere Version von tar(1.15.1) nur ausschließen würde, wenn sich das oberste Verzeichnis zuletzt in der Befehlszeile befindet. Dies ist genau das Gegenteil von der Version 1.23. Zu Ihrer Information.

ateiob
quelle

Antworten:

50

Wenn Sie ein gesamtes Verzeichnis ausschließen möchten, sollte Ihr Muster mit diesem Verzeichnis übereinstimmen, nicht mit den darin enthaltenen Dateien. Verwenden Sie --exclude=/data/sub1anstelle von--exclude='/data/sub1/*'

Achten Sie darauf, die Muster in Anführungszeichen zu setzen, um sie vor der Expansion der Schale zu schützen.

Sehen Sie sich dieses Beispiel mit Problemen beim letzten Aufruf an:

$ for i in 0 1 2; do mkdir -p /tmp/data/sub$i; echo foo > /tmp/data/sub$i/foo; done
$ find /tmp/data
/tmp/data
/tmp/data/sub2
/tmp/data/sub2/foo
/tmp/data/sub0
/tmp/data/sub0/foo
/tmp/data/sub1
/tmp/data/sub1/foo
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude='/tmp/data/sub[1-2]'
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub0/
/tmp/data/sub0/foo
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub0/
/tmp/data/sub0/foo
$ echo tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub[1-2]
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub2/
/tmp/data/sub2/foo
/tmp/data/sub0/
/tmp/data/sub0/foo
/tmp/data/sub2/
tar: Removing leading `/' from hard link targets
/tmp/data/sub2/foo
$ echo tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub[1-2]
tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub1 /tmp/data/sub2
R Perrin
quelle
Vielen Dank für die sehr fokussierte und klare Antwort. In Bezug auf Ihren ersten Punkt habe ich versucht, den Tipps in diesem LQ-Thread zu folgen . Ich bin mir nicht sicher, was ich verpasst habe, aber jetzt, da ich Ihren zweiten Punkt gelesen habe, kann es durchaus ein absolutes vs. relatives Pfadproblem sein. Ich werde das versuchen und berichten. +1 für jetzt.
Ateiob
Eine andere Sache , die ich bemerkt , ist der --exclude b(Raum statt Gleichheitszeichen) vs. --exclude=b. Macht das einen Unterschied? (sollte nicht IMHO)
ateiob
1
Das Gleichheitszeichen kann wichtig sein, um die Erweiterung von nicht zitierten Mustern durch die Shell zu vermeiden. Wenn Sie stattdessen ein Leerzeichen haben, kann ein nicht in Anführungszeichen gesetztes Muster von der Shell zu einem einzelnen --exclude-Argument erweitert werden, und die verbleibenden Erweiterungen werden als Dateien zum Hinzufügen zur tar-Datei angegeben. Ihre Beispiele haben vor allem '=' - wenn das Skript keine einfachen Anführungszeichen enthält, kann dies die Ursache Ihres Problems sein.
R Perrin
OKAY. Ich habe dein Beispiel auf meiner Box getestet und es funktioniert auch mit mehreren --exclude=auf derselben Leitung. Der Unterschied muss also der Schwachsinn sein /*, den ich an jedes Unterverzeichnis angehängt habe. Ich werde dies heute Abend im Produktionsskript testen und darüber berichten. Ein weiteres +1.
Ateiob
Für mich war die Antwort von @carlo das spezifische Problem - dummer Teer kann das nicht akzeptieren - als letzte Option in der Befehlszeile ausschließen - was offensichtlich viele Kopfschmerzen verursacht. Vielen Dank an alle.
Moodboom
32

Möglicherweise tarerfordert Ihre Version von , dass die --excludeOptionen am Anfang des tarBefehls platziert werden müssen.

Siehe: https://stackoverflow.com/q/984204

tar --exclude='./folder' --exclude='./upload/folder2' \
    -zcvf /backup/filename.tgz .

Siehe: http://mandrivausers.org/index.php?/topic/8585-multiple-exclude-in-tar/

tar --exclude=<first> --exclude=<second> -cjf backupfile.bz2 /home/*

Alternative:

EXCLD='first second third'
tar -X <(for i in ${EXCLD}; do echo $i; done) -cjf backupfile.bz2 /home/*

Ein weiterer tarBefehlstipp ist von hier :

tar cvfz myproject.tgz --exclude='path/dir_to_exclude1' \
                       --exclude='path/dir_to_exclude2' myproject
carlo
quelle
Siehe mein Update oben. Die letzte versuchte Variante (keine Anführungszeichen, Leerzeichen) funktioniert. Ich habe keine Idee warum. +1 für die gut durchdachte Antwort + Links.
Ateiob
Zu --exclude=mydir/*Ihrer Information , unter debian, Wenn ich den Filter nicht genau angebe, funktioniert er nicht (mit tar --exclude=maindir/mydir/* -cjf archive.tar2.bz2 maindir/*).
Olivier Pons
1
@OlivierPons anstelle von "under debian" oder vielleicht mit der Version von tar ( tar --version); debian wird im Laufe der Jahre vermutlich mit vielen verschiedenen Versionen von tar ausgeliefert.
Msouth
1
Meine Version (1.29) funktioniert nur mit --excludevorher -czf.
falsePockets
8

Versuchen Sie, mehrere Dateien auszuschließen

--exclude=/data/{sub1,sub2,sub3,sub4}

Das spart Code und Kopfschmerzen. Dies ist eine globale Lösung für alle Arten von Programmen / Optionen. Wenn Sie auch das übergeordnete Verzeichnis in Ihre Auswahl aufnehmen möchten (in diesem Fall Daten), müssen Sie ein nachstehendes Komma einfügen. Z.B:

umount /data/{sub1,sub2,}
tolga9009
quelle
3
Ich liebe Locken. Ich finde, dass viele Leute nichts über sie wissen, auch wenn sie jahrelange Erfahrung mit Unix haben. mv /very/very/very/very/long/path/to/a/file{,.bak}
Msouth
5

Dieser Link könnte hilfreich sein. http://answers.google.com/answers/threadview/id/739467.html

Zwei unmittelbare Unterschiede zwischen der nicht funktionierenden Zeile und einigen Tipps im Link:

  1. Alle umfassen nicht kommt nach dem Top-Level - Verzeichnis.
  2. Nach dem letzten darf KEIN Leerzeichen stehen --exclude.
BigG
quelle
Vielen Dank. Die Antwort von -MAKerregte meine Aufmerksamkeit und bis jetzt konnte ich die folgenden Unterschiede zwischen meiner nicht arbeitenden Zeile und den folgenden feststellen: 1. Alle Ausschlüsse folgen nach dem Verzeichnis der obersten Ebene. 2. Nach dem letzten darf KEIN Leerzeichen stehen --exclude. Ich werde diese Erkenntnisse testen und berichten. +1 für jetzt.
Ateiob
@Dateiob Wenn Sie es herausfinden, können Sie hier eine Antwort posten oder diese bearbeiten? Wir bevorzugen im Allgemeinen keine Antworten, die nur Links an anderer Stelle sind
Michael Mrozek
@ Michael Mrozek Auf jeden Fall. Genau das habe ich in meinem Kommentar geschrieben. :)
ateiob
3

Eine Problemumgehung kann darin bestehen, eine Kombination von find ... -pruneund tarzum Ausschließen der angegebenen Verzeichnisse zu verwenden.

Unter Mac OS X scheint die --excludeOption von GNU jedoch tarso zu funktionieren, wie sie sollte.

Im folgenden Testfall sollen die Verzeichnisse /private/var/log/aslund /private/var/log/DiagnosticMessagesaus einem komprimierten Archiv des /private/var/logVerzeichnisses ausgeschlossen werden.

# all successfully tested in Bash shell on Mac OS X (using gnutar and gfind)

# sudo port install findutils  # for gfind from MacPorts

sudo gnutar -czf ~/Desktop/varlog.tar.gz /private/var/log --exclude "/private/var/log/asl" --exclude "/private/var/log/DiagnosticMessages"

sudo gnutar -czf ~/Desktop/varlog.tar.gz  --exclude "/private/var/log/asl" --exclude "/private/var/log/DiagnosticMessages" /private/var/log

set -f # disable file name globbing
sudo gnutar -czf ~/Desktop/varlog.tar.gz  --exclude "/private/var/log/asl" --exclude "/private/var/log/Diagnostic*" /private/var/log

# combining GNU find and tar (on Mac OS X)

sudo gfind /private/var/log -xdev -type d \( -name "asl" -o -name "DiagnosticMessages" \) -prune -o -print0 | 
   sudo gnutar --null --no-recursion -czf ~/Desktop/varlog.tar.gz --files-from -

# exclude even more dirs
sudo gfind /private/var/log -xdev -type d \( -name "asl" -o -name "[Dacfks]*" \) -prune -o -print0 | 
    sudo gnutar --null --no-recursion -czf ~/Desktop/varlog.tar.gz --files-from -


# testing the compressed archive

gnutar -C ~/Desktop -xzf ~/Desktop/varlog.tar.gz

sudo gfind /private/var/log ~/Desktop/private \( -iname DiagnosticMessages -or -iname asl \)

sudo rm -rf ~/Desktop/varlog.tar.gz ~/Desktop/private
jon
quelle
Danke +1 für den Vorschlag. An diesem Punkt versuche ich immer noch zu verstehen, warum ein gut dokumentiertes (und ausgereiftes) Feature in meinem Skript nicht funktioniert, das jede Nacht von Cron ausgeführt wird.
Ateiob
3

Vielleicht können Sie den Befehl mit einer anderen Option versuchen:

--wildcards

Und prüfen Sie, ob es wie vorgesehen ausgeführt wird.

Luis
quelle
Siehe mein Update oben. Die letzte versuchte Variante (keine Anführungszeichen, Leerzeichen) funktioniert. Ich habe keine Idee warum. +1 für die Idee.
Ateiob
3

Ich benutze einen Mac und habe festgestellt, dass Ausschlüsse nur dann funktionieren, wenn der Ordner der obersten Ebene das letzte Argument ist

Beispiel eines Arbeitsbefehls:

tar czvf tar.tgz --exclude='Music' dir

Zu Ihrer Information:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3
jars99
quelle
Gleiches gilt für tar 1.27.1 über Ubuntu 14.04.
Greg Bell
3

In meinem Fall hat es aus einem anderen Grund nicht ausgeschlossen.

Der vollständige Pfad im Vergleich zum relativen Pfad.

Sowohl der Ausschluss als auch das Verzeichnis müssen dasselbe Pfadformat verwenden (dh beide vollständigen Pfade oder beide relativen Pfade).

Beispiel:

tar -cvf ctms-db-sync.tar --exclude='/home/mine/tmp/ctms-db-sync/sql' ctms-db-sync

Dies funktioniert nicht, da beim Ausschließen der vollständige Pfad verwendet wird, während das Ziel einen relativen Pfad verwendet

tar -cvf ctms-db-sync.tar --exclude='/home/mine/tmp/ctms-db-sync/sql' /home/mine/tmp/ctms-db-sync

Dies funktioniert, weil beide den vollständigen Pfad verwenden

tar -cvf ctms-db-sync.tar --exclude='ctms-db-sync/sql' ctms-db-sync

Dies funktioniert, weil beide den relativen Pfad verwenden

hbt
quelle
1

Zusätzliche Anmerkungen zu R Perrins hervorragender Antwort :

Angenommen, Sie möchten keine absoluten, sondern relative Pfade archivieren, z. B. 'data' anstelle von '/ tmp / data'. Um absolute Pfade auszuschließen, unterscheiden sich Ihre tar-Argumente je nach der von Ihnen verwendeten tar-Implementierung (gnu tar vs. bsd tar):

$ for i in 0 1 2; do
    for j in 0 1 2; do 
      mkdir -p /tmp/data/sub$i/sub$j
      echo foo > /tmp/data/sub$i/sub$j/foo
    done
  done

$ find /tmp/data/
/tmp/data/
/tmp/data/sub2
/tmp/data/sub2/sub2
/tmp/data/sub2/sub2/foo
/tmp/data/sub2/sub1
/tmp/data/sub2/sub1/foo
/tmp/data/sub2/sub0
/tmp/data/sub2/sub0/foo
/tmp/data/sub1
/tmp/data/sub1/sub2
/tmp/data/sub1/sub2/foo
/tmp/data/sub1/sub1
/tmp/data/sub1/sub1/foo
/tmp/data/sub1/sub0
/tmp/data/sub1/sub0/foo
/tmp/data/sub0
/tmp/data/sub0/sub2
/tmp/data/sub0/sub2/foo
/tmp/data/sub0/sub1
/tmp/data/sub0/sub1/foo
/tmp/data/sub0/sub0
/tmp/data/sub0/sub0/foo

$ cd /tmp/data; tar -zvcf /tmp/_data.tar --exclude './sub[1-2]'
./
./sub0/
./sub0/sub2/
./sub0/sub2/foo
./sub0/sub1/
./sub0/sub1/foo
./sub0/sub0/
./sub0/sub0/foo

# ATTENTION: bsdtar's behaviour differs from traditional tar (without a leading '^')!
$ cd /tmp/data; bsdtar -zvcf /tmp/_data.tar --exclude './sub[1-2]' .
a .
a ./sub0
a ./sub0/sub0
a ./sub0/sub0/foo

# FIX: Use a regex by adding a leading '^' will cause bsdtar to match only parent files and folders.
$ cd /tmp/data; bsdtar -zvcf /tmp/_data.tar --exclude '^./sub[1-2]' .
# ALTERNATIVE: bsdtar -C /tmp/data -zvcf /tmp/_data.tar --exclude '^./sub[1-2]' .
a .
a ./sub0
a ./sub0/sub2
a ./sub0/sub1
a ./sub0/sub0
a ./sub0/sub0/foo
a ./sub0/sub1/foo
a ./sub0/sub2/foo
Jakob
quelle
1

Gerade erst auf Teer (GNU Teer) 1.29 erkannt

Dieser Aufruf schließt Archivdateien, die mit --exclude-from angegeben wurden, nicht aus:

/bin/tar --files-from ${datafile} --exclude-from ${excludefile} -jcf ${backupfile}

Dieser Aufruf funktioniert korrekt:

/bin/tar --exclude-from ${excludefile} --files-from ${datafile} -jcf ${backupfile}

Reihenfolge der Parameter ist wichtig!

Alexander
quelle
0

Ich habe alle möglichen Kombinationen ausprobiert, einschließlich einiger der aufgelisteten Antworten, und konnte es einfach nicht schaffen, die aufgelisteten Dateien auszuschließen.

Als ich es satt hatte, die Antwort auf einen Fünf-Minuten-Job zu suchen, tat ich das Gegenteil: Ich erstellte ein Archiv der Ordner, die ich einschließen wollte .

Ich habe dazu ein Archiv erstellt und dieses dann hinzugefügt :

tar -cvpf /path/to/mybackup.tar ./bin
tar rvf /path/to/mybackup.tar ./boot
tar rvf /path/to/mybackup.tar ./etc
tar rvf /path/to/mybackup.tar ./home
tar rvf /path/to/mybackup.tar ./lib
tar rvf /path/to/mybackup.tar ./sbin
tar rvf /path/to/mybackup.tar ./usr
tar rvf /path/to/mybackup.tar ./var

Ein paar Anmerkungen:

  • Ich habe die relativen Pfade anstelle der absoluten Pfade (die ebenfalls Probleme bereiteten) verwendet, indem ich vom Stammverzeichnis des Dateisystems aus lief.
  • Sie müssen ein einfaches tar(und nicht komprimiertes tar .tgz/ .tar.gz) Archiv erstellen - Sie können es später mit komprimierengzip mybackup.tar
  • Stellen Sie sicher, dass Sie das Archiv nicht in einem Ordner ablegen, den Sie einschließen, da sonst eine Rekursion auftritt (eine teilweise Sicherung, die auch in der Sicherung selbst enthalten ist).
  • Beachten Sie den Unterschied zwischen dem ersten Befehl (Erstellen) und den anderen Befehlen (Hinzufügen).
  • Sie können überprüfen, ob Dateien hinzugefügt werden, anstatt die Sicherung zu überschreiben (z. B. nach dem zweiten Befehl), wenn Sie paranoid sind, indem Sie verwenden tar tvf mybackup.tar.
SharpC
quelle