tar --exclude non esclude. Perché?


71

Ho questa riga molto semplice in uno script bash che viene eseguito correttamente (ovvero producendo il _data.tarfile), tranne per il fatto che non esclude le sottodirectory che gli viene detto di escludere tramite l' --excludeopzione:

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

Invece, produce un _data.tarfile che contiene tutto in / dati, inclusi i file nelle sottodirectory che volevo escludere.

Qualche idea sul perché? e come risolvere questo?

Aggiornamento Ho implementato le mie osservazioni in base al link fornito nella prima risposta di seguito (dir di primo livello, senza spazi vuoti dopo l'ultima esclusione):

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

Ma questo non ha aiutato. Tutte le sottodirectory "escluse" sono presenti nel _data.tarfile risultante .

Questo è sconcertante. Che si tratti di un bug nel tar corrente (GNU tar 1.23, su CentOS 6.2, Linux 2.6.32) o "estrema sensibilità" del tar verso gli spazi bianchi e altri errori di battitura facili da perdere, lo considero un bug. Per adesso.

Questo è orribile : ho provato le intuizioni suggerite di seguito (nessuna traccia /*) e non funziona ancora nello script di produzione:

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

Non riesco a vedere alcuna differenza tra quello che ho provato e quello che ha provato @Richard Perrin, tranne le virgolette e 2 spazi invece di 1. Ho intenzione di provare questo (devo aspettare che lo script notturno venga eseguito come directory per il backup è enorme) e riferire.

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

Sto cominciando a pensare che tutte queste tar --excludesensibilità non sono catrame ma qualcosa nel mio ambiente, ma allora cosa potrebbe essere?

Ha funzionato! L'ultima variante ha provato a funzionare (senza virgolette singole e spazio singolo anziché doppio spazio tra le --excludes) testato funzionante. Strano ma accettante.

Incredibile! Si scopre che una versione precedente di tar(1.15.1) escluderebbe solo se la directory di livello superiore è l' ultima nella riga di comando. Questo è l'esatto contrario di come richiede la versione 1.23. PER TUA INFORMAZIONE.

Risposte:


50

Se si desidera escludere un'intera directory, il modello deve corrispondere a quella directory, non ai file al suo interno. Usa --exclude=/data/sub1invece di--exclude='/data/sub1/*'

Fare attenzione a citare i motivi per proteggerli dall'espansione della shell.

Vedi questo esempio, con problemi nell'invocazione finale:

$ 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

Grazie per la risposta molto focalizzata e chiara. Per quanto riguarda il tuo primo punto, stavo cercando di seguire i suggerimenti in questo thread di LQ . Non sono sicuro di cosa mi sono perso, ma ora che ho letto il tuo secondo punto, potrebbe benissimo essere un problema di percorso assoluto rispetto a quello relativo. Lo proverò e riporterò indietro. +1 per ora.
ateiob,

Un'altra cosa che ho notato è il --exclude b(spazio invece di segno uguale) vs. --exclude=b. Questo fa qualche differenza? (non dovrei IMHO)
ateiob il

1
Il segno uguale può essere essenziale per evitare l'espansione della shell di schemi non quotati. Se invece si dispone di uno spazio, un modello non quotato può essere espanso dalla shell in un singolo argomento --exclude e le espansioni rimanenti vengono fornite come file da aggiungere al file tar. Soprattutto i tuoi esempi hanno '=' - se lo script non lo fa e mancano virgolette singole, questo può essere la fonte del tuo problema.
R Perrin,

OK. Ho testato il tuo esempio sulla mia scatola e funziona, anche con multipli --exclude=sulla stessa linea. Quindi la differenza deve essere l'idiota /*che ho aggiunto a ogni sottodirectory. Lo testerò stasera nella sceneggiatura di produzione e riferirò indietro. Un altro +1.
ateiob,

Per me, la risposta di @carlo è stata il problema specifico - lo stupido tar non può accettare - esclude come ultima opzione sulla riga di comando - ovviamente causando molti mal di testa. Ringrazia tutti.
moodboom

34

È possibile che la tua versione tarrichieda che le --excludeopzioni debbano essere posizionate all'inizio del tarcomando.

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

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

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

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

Alternativa:

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

Un altro tarsuggerimento è da qui :

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

Vedi il mio aggiornamento sopra. L'ultima variante provata (senza virgolette, spazio singolo) funziona. Non ho idea del perché. +1 per la risposta ben ponderata + collegamenti.
ateiob il

Cordiali saluti, sotto Debian, se non preciso il filtro, come --exclude=mydir/*allora non funziona (usando tar --exclude=maindir/mydir/* -cjf archive.tar2.bz2 maindir/*).
Olivier Pons,

1
@OlivierPons piuttosto che "under debian", o forse con esso, inserisci la versione di tar ( tar --version); presumibilmente, nel corso degli anni, Debian verrà spedito con molte versioni diverse di tar.
msouth,

1
La mia versione (1.29) funziona solo con --excludeprima -czf.
falsePockets

8

Per escludere più file, provare

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

Ciò farà risparmiare un po 'di codice e mal di testa. Questa è una soluzione globale, per tutti i tipi di programmi / opzioni. Se si desidera includere anche la directory principale nella selezione (in questo caso i dati), è necessario includere una virgola finale. Per esempio:

umount /data/{sub1,sub2,}

3
Adoro i ricci. Trovo che molte persone non ne siano a conoscenza, anche con anni di esperienza in Unix. mv /very/very/very/very/long/path/to/a/file{,.bak}
msouth,

5

Questo link potrebbe essere utile. http://answers.google.com/answers/threadview/id/739467.html

Due differenze immediate tra la linea non operativa e alcuni suggerimenti nel collegamento:

  1. Tutte le esclusioni vengono dopo la directory di livello superiore.
  2. Impossibile avere QUALSIASI spazio dopo l'ultimo --exclude.

Grazie. La risposta di ha -MAKattirato la mia attenzione e finora sono stato in grado di individuare le seguenti differenze tra la mia linea non funzionante e le seguenti: 1. Tutte le esclusioni vengono dopo la directory di livello superiore. 2. Impossibile avere QUALSIASI spazio dopo l'ultimo --exclude. Metterò alla prova queste intuizioni e riferirò. +1 per ora.
ateiob,

@ateiob Se lo capisci, puoi pubblicare una risposta qui o modificarla? Preferiamo generalmente non avere risposte che sono solo link altrove
Michael Mrozek

@Michael Mrozek Assolutamente. Questo è esattamente ciò che ho scritto nel mio commento. :)
ateiob il

3

Una soluzione alternativa potrebbe essere quella di utilizzare una combinazione di find ... -pruneed tarescludere le directory specificate.

Su Mac OS X l' --excludeopzione di GNU tarsembra funzionare come dovrebbe però.

Nel seguente caso di test le directory /private/var/log/asle /private/var/log/DiagnosticMessagesdevono essere escluse da un archivio compresso della /private/var/logdirectory.

# 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

Grazie +1 per il suggerimento. A questo punto sto ancora cercando di capire perché una funzione ben documentata (e matura) non funziona nella mia sceneggiatura, gestita di notte da cron.
ateiob,

3

Forse puoi provare il comando con un'altra opzione:

--wildcards

E controlla se funziona come previsto.


Vedi il mio aggiornamento sopra. L'ultima variante provata (senza virgolette, spazio singolo) funziona. Non ho idea del perché. +1 per l'idea.
ateiob il

3

Sto usando un mac e ho scoperto che non funzionava a meno che la cartella di livello superiore non fosse l'ultimo argomento

esempio di comando funzionante:

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

PER TUA INFORMAZIONE:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3

Lo stesso vale con tar 1.27.1 tramite Ubuntu 14.04.
Greg Bell,

3

Nel mio caso, non è stato escluso per un motivo diverso.

Il percorso completo vs percorso relativo.

Sia l'esclusione che la directory devono utilizzare lo stesso formato di percorso (ovvero sia il percorso completo che entrambi i percorsi relativi)

Esempio:

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

Questo non funzionerà perché exclude utilizza il percorso completo in cui la destinazione utilizza un percorso relativo

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

Questo funziona perché entrambi utilizzano il percorso completo

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

Questo funziona perché entrambi utilizzano il percorso relativo



1

Note aggiuntive all'ottima risposta di R Perrin :

Supponiamo di non voler archiviare percorsi assoluti ma relativi, ad esempio "dati" anziché "/ tmp / dati". Per escludere percorsi assoluti, i tuoi argomenti tar differiranno in base all'implementazione tar (gnu tar vs. bsd tar) che usi:

$ 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

Appena rilevato su tar (GNU tar) 1.29

Questa chiamata non esclude dai file di archivio specificati con --exclude-da:

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

Questa chiamata funziona in modo coerente:

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

L'ordine dei parametri è importante!


0

Ho provato tutti i tipi di combinazioni tra cui alcune delle risposte elencate e non riuscivo a escludere i file elencati.

Quindi, stufo di inseguire la risposta a quello che doveva essere un lavoro di cinque minuti, ho fatto il contrario: ho creato un archivio delle cartelle che volevo includere.

L'ho fatto creando un archivio e poi aggiungendo ad esso :

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

Alcune note:

  • Ho usato i percorsi relativi anziché assoluti (che davano anche problemi) eseguendo dalla radice del filesystem.
  • Devi creare un archivio semplice tar(e non compresso con tar .tgz/ .tar.gz) - puoi comprimerlo in un secondo momento usandogzip mybackup.tar
  • Assicurati di non mettere l'archivio in nessuna cartella che stai includendo o otterrai una ricorsione (un backup parziale incluso anche nel backup stesso).
  • Nota la differenza nel primo comando (crea) dagli altri (aggiungi).
  • È possibile verificare che i file vengano aggiunti anziché il backup sovrascritto (ad esempio dopo il secondo comando) se si è paranoici utilizzando tar tvf mybackup.tar.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.