web-dev-qa-db-fra.com

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'est-à-dire produire le _data.tar fichier), sauf qu'il ne le fait pas exclut les sous-répertoires qu'il est dit d'exclure via le --exclude option:

/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 _data.tar fichier qui contient tout sous/data, y compris les fichiers dans les sous-répertoires que je voulais exclure.

Une idée pourquoi? et comment y remédier?

Mise à jour J'ai implémenté mes observations sur la base du lien fourni dans la première réponse ci-dessous (répertoire de premier niveau en premier, pas d'espaces 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-répertoires "exclus" sont présents dans le _data.tar fichier.

C'est déroutant. Que ce soit un bogue dans tar actuel (GNU tar 1.23, sur un CentOS 6.2, Linux 2.6.32) ou une "sensibilité extrême" de tar aux espaces blancs et autres fautes de frappe faciles à manquer, je considère que c'est un bogue. Pour l'instant.

C'est horrible: J'ai essayé la perspicacité suggérée ci-dessous (pas de fin /*) 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é, sauf pour les guillemets et 2 espaces au lieu de 1. Je vais essayer ceci (doit attendre que le script nocturne s'exécute comme répertoire à sauvegarder) est énorme) et faire rapport.

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

Je commence à penser que tous ces tar --exclude les sensibilités ne sont pas du goudron, mais quelque chose dans mon environnement, mais qu'est-ce que cela pourrait être?

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

Incroyable! Il s'avère qu'une ancienne version de tar (1.15.1) n'exclurait que si le répertoire de niveau supérieur est last sur la ligne de commande . C'est exactement le contraire de la façon dont la version 1.23 nécessite. Pour info.

78
ateiob

Si vous souhaitez exclure un répertoire entier, votre modèle doit correspondre à ce répertoire, pas aux fichiers qu'il contient. Utilisation --exclude=/data/sub1 au lieu de --exclude='/data/sub1/*'

Soyez prudent en citant les modèles pour les protéger de l'expansion de Shell.

Voir cet exemple, avec des problèmes lors de 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
55
R Perrin

Il se peut que votre version de tar nécessite que le --exclude les options doivent être placées au début de la commande 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 commande tar vient de ici :

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

Pour exclure plusieurs fichiers, essayez

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

Cela permettra d'économiser du code et des maux de tête. Il s'agit d'une solution globale, pour tout type de programmes/options. Si vous souhaitez également inclure le répertoire parent dans votre sélection (dans ce cas, les données), vous devez inclure une virgule de fin. Par exemple.:

umount /data/{sub1,sub2,}
8
tolga9009

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

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

  1. Tous les exclus viennent après le répertoire de niveau supérieur.
  2. Ne peut contenir AUCUN espace après le dernier --exclude.
5
BigG

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

exemple de commande de travail:

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

Pour info:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3
5
jars99

Vous pouvez peut-être essayer la commande avec une autre option:

--wildcards

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

3
Luis

Une solution de contournement peut consister à utiliser une combinaison de find ... -Prune et tar pour exclure les répertoires spécifiés.

Sous Mac OS X, le --exclude l'option de GNU tar semble fonctionner correctement.

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

# 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
3
jon

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

Le chemin complet vs chemin relatif.

L'exclusion et le répertoire doivent utiliser le même format de chemin (c'est-à-dire le chemin complet ou les deux chemins 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 chemin complet alors que la cible utilise un chemin relatif

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

Cela fonctionne car les deux utilisent le chemin complet

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

Cela fonctionne car les deux utilisent le chemin relatif

3
hbt
1
Ender

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

Supposons que vous ne souhaitiez pas archiver des chemins absolus mais relatifs, par exemple 'data' au lieu de '/ tmp/data'. Pour exclure les chemins absolus, vos arguments tar différeront 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
1
Jakob

À peine détecté sur tar (GNU tar) 1.29

Cet appel n'exclut pas des fichiers d'archive spécifiés avec --exclude-from:

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

Cet appel fonctionne de manière coordonnée:

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

L'ordre des paramètres est important!

1
Alexander

J'ai essayé toutes sortes de combinaisons, y compris quelques-unes des réponses répertoriées et je n'ai tout simplement pas réussi à exclure les fichiers répertoriés.

Donc, marre de courir après la réponse à ce qui devait être un travail de cinq minutes, j'ai fait le contraire: j'ai créé une archive des dossiers que je voulais comprendre.

Je l'ai fait en créant une archive puis en y ajoutant :

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

Quelques notes:

  • J'ai utilisé le chemin relatif au lieu des chemins absolus (qui causaient également des problèmes) en exécutant à partir de la racine du système de fichiers.
  • Vous devez créer une archive tar simple (et non zippée tar .tgz/.tar.gz) - vous pouvez la compresser plus tard en utilisant gzip mybackup.tar
  • Assurez-vous de ne pas mettre l'archive dans un dossier que vous incluez ou vous obtiendrez une récursivité (une sauvegarde partielle également incluse dans la sauvegarde elle-même).
  • Notez la différence entre la première commande (créer) et les autres (ajouter).
  • Vous pouvez vérifier que les fichiers sont ajoutés plutôt que la sauvegarde remplacée (par exemple après la deuxième commande) si vous êtes paranoïaque en utilisant tar tvf mybackup.tar.
1
SharpC