tar –exclude n'exclut pas. Pourquoi?

J'ai cette ligne très simple dans un script bash qui s'exécute avec succès (c.-à-d. Produisant le file _data.tar ), excepté qu'elle n'exclut pas les sous-directorys --exclude on dit exclure via l'option --exclude :

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

Au lieu de cela, il produit un file _data.tar qui contient tout sous / data, y compris les files dans les sous-directorys que je voulais exclure.

Une idée pourquoi? et comment résoudre ce problème?

Mise à jour J'ai implémenté mes observations en fonction du lien fourni dans la première réponse ci-dessous (premier niveau dir, pas d'espace après la dernière exclusion):

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

Mais cela n'a pas aidé. Tous les sous-directorys "exclus" sont présents dans le file _data.tar résultant.

C'est déroutant. Qu'il s'agisse d'un bogue dans le tar actuel (GNU tar 1.23, sur un CentOS 6.2, Linux 2.6.32) ou de «sensibilité extrême» du tar sur les espaces blancs et autres fautes de frappe faciles à percevoir, je considère cela comme un bug. Pour l'instant.

C'est horrible : j'ai essayé la perspicacité suggérée ci-dessous (pas de fuite /* ) et cela ne fonctionne toujours pas dans le script de production:

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

Je ne vois aucune différence entre ce que j'ai essayé et ce que @Richard Perrin a essayé, à l'exception des guillemets et de 2 espaces au lieu de 1. Je vais essayer ceci (je dois attendre que le script du soir s'exécute comme directory à sauvegarder up est énorme) et rendre count.

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

Je commence à penser que toutes ces sensibilités de tar --exclude pas le goudron mais quelque chose dans mon environnement, mais alors qu'est-ce que cela pourrait être?

Ça a marché! La dernière variante essayée (pas de guillemets simples et d'espace unique au lieu d'un double-espace entre les --exclude ) testé fonctionne. Bizarre mais acceptant.

Incroyable! Il s'avère qu'une ancienne version de tar (1.15.1) n'exclurait que si le directory de niveau supérieur était le dernier sur la command line. C'est exactement le contraire de la version 1.23. Pour info.

    Si vous souhaitez exclure un directory entier, votre model doit correspondre à ce directory, et non aux files qu'il contient. Utilisez --exclude=/data/sub1 au lieu de --exclude='/data/sub1/*'

    Soyez prudent en citant les motifs pour les protéger de l'expansion de la coquille.

    Voir cet exemple, avec des problèmes dans l'appel final:

     $ 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 

    Il se peut que votre version de tar nécessite que les options --exclude soient placées au début de la command tar .

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

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

    Voir: 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/* 

    Encore une autre astuce de command tar est d' ici :

     tar cvfz myproject.tgz --exclude='path/dir_to_exclude1' \ --exclude='path/dir_to_exclude2' myproject 

    Pour exclure plusieurs files, essayez

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

    Cela permettra d'économiser du code et des maux de tête. Ceci est une solution globale, pour tous les types de programmes / options. Si vous souhaitez également inclure le directory parent dans votre sélection (dans ce cas, datatables), vous devez inclure une virgule de fin. Par exemple:

     umount /data/{sub1,sub2,} 

    Ce lien pourrait être utile. http://answers.google.com/answers/threadview/id/739467.html

    Deux différences immédiates entre la ligne de non-travail et quelques conseils dans le lien:

    1. Tout exclut vient après le directory de premier niveau.
    2. Ne peut avoir aucun espace après le dernier --exclude .

    Une solution de contournement peut être d'utiliser une combinaison de find ... -prune et tar pour exclure les directorys spécifiés.

    Sur Mac OS X, l'option --exclude de GNU tar semble fonctionner comme il se doit.

    Dans le cas de test suivant, les directorys /private/var/log/asl et /private/var/log/DiagnosticMessages doivent être exclus d'une archive compressée du directory /private/var/log .

     # 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 

    Peut-être que vous pouvez essayer la command avec une autre option:

     --wildcards 

    Et vérifiez s'il fonctionne comme prévu.

    J'utilise un mac, et a constaté que les excludes ne fonctionnaient pas sauf si le dossier de niveau supérieur est le dernier argument

    exemple de command de travail:

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

    Pour information:

     $: tar --version bsdtar 2.8.3 - libarchive 2.8.3 

    Dans mon cas, cela n'a pas exclu pour une raison différente.

    Le path complet par rapport au path relatif.

    Le directory d'exclusion et le directory doivent utiliser le même format de path (c'est-à-dire le path complet ou les deux paths relatifs)

    Exemple:

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

    Cela ne fonctionnera pas car exclure utilise le path complet où la cible utilise un path relatif

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

    Cela fonctionne parce que les deux utilisent le path complet

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

    Cela fonctionne parce que les deux utilisent le path relatif

    Notes supplémentaires à l'excellente réponse de R Perrin :

    Supposons que vous ne souhaitiez pas archiver les paths absolus mais relatifs, par exemple 'data' au lieu de '/ tmp / data'. Pour exclure les paths absolus, vos arguments tar seront différents en fonction de l'implémentation tar (gnu tar vs. bsd tar) que vous utilisez:

     $ 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