tar --exclude nie wyklucza. Dlaczego?


71

Mam tę bardzo prostą linię w skrypcie bash, który wykonuje się pomyślnie (tj. Produkuje _data.tarplik), z tym wyjątkiem, że nie wyklucza podkatalogów, o których mówi się wykluczenie za pomocą --excludeopcji:

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

Zamiast tego tworzy _data.tarplik, który zawiera wszystko w katalogu / data, w tym pliki w podkatalogach, które chciałem wykluczyć.

Masz pomysł, dlaczego? i jak to naprawić?

Aktualizacja Zaimplementowałem swoje obserwacje na podstawie linku podanego w pierwszej odpowiedzi poniżej (najpierw najwyższy poziom, brak spacji po ostatnim wykluczeniu):

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

Ale to nie pomogło. Wszystkie „wykluczone” podkatalogi są obecne w _data.tarpliku wynikowym .

To zastanawia. Niezależnie od tego, czy jest to błąd w bieżącym pliku tar (GNU tar 1.23, na CentOS 6.2, Linux 2.6.32), czy też „ekstremalna wrażliwość” tar na białe spacje i inne łatwe do pominięcia literówki, uważam to za błąd. Na razie.

To jest okropne : wypróbowałem wgląd sugerowany poniżej (bez końcowego /*) i nadal nie działa w skrypcie produkcyjnym:

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

Nie widzę żadnej różnicy między tym, co próbowałem, a tym, co próbował @Richard Perrin, z wyjątkiem cudzysłowów i 2 spacji zamiast 1. Zamierzam spróbować (muszę poczekać na uruchomienie nocnego skryptu jako katalogu, którego kopię zapasową chcesz wykonać) jest ogromny) i zgłoś się.

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

Zaczynam myśleć, że wszystkie te tar --excludewrażliwości to nie smoła, ale coś w moim środowisku, ale co to może być?

Zadziałało! Ostatnia wypróbowana odmiana (bez pojedynczych cudzysłowów i pojedynczej spacji zamiast podwójnej spacji między --excludes) przetestowana działająca. Dziwne, ale akceptujące.

Nie do wiary! Okazuje się, że starsza wersja tar(1.15.1) wyklucza się tylko wtedy, gdy katalog najwyższego poziomu jest ostatni w linii poleceń. Jest to dokładne przeciwieństwo wymagań wersji 1.23. FYI.

Odpowiedzi:


50

Jeśli chcesz wykluczyć cały katalog, wzorzec powinien pasować do tego katalogu, a nie znajdujących się w nim plików. Użyj --exclude=/data/sub1zamiast--exclude='/data/sub1/*'

Zachowaj ostrożność przy cytowaniu wzorów, aby chronić je przed rozszerzaniem się powłoki.

Zobacz ten przykład z problemami z ostatnim wywołaniem:

$ 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

Dzięki za bardzo skoncentrowaną i jasną odpowiedź. Jeśli chodzi o twój pierwszy punkt, starałem się podążać za wskazówkami w tym wątku LQ . Nie jestem pewien, co przeoczyłem, ale teraz, kiedy przeczytałem twój drugi punkt, może to być absolutnie problem względnej ścieżki. Spróbuję tego i zdam raport. Na razie +1.
ateiob

Inną rzeczą, jaką zauważyłem jest --exclude b(spacja zamiast znaku równości) vs. --exclude=b. Czy to robi różnicę? (nie powinien IMHO)
ateiob

1
Znak równości może być niezbędny, aby uniknąć ekspansji powłoki niecytowanych wzorców. Jeśli zamiast tego masz spację, wówczas niecytowany wzorzec może zostać rozwinięty przez powłokę w pojedynczy argument - wyklucz, a pozostałe rozszerzenia dają pliki do dodania do pliku tar. Twoje przykłady mają przede wszystkim „=” - jeśli skrypt nie ma i brakuje pojedynczych cudzysłowów, może to być źródłem problemu.
R Perrin

DOBRZE. Przetestowałem twój przykład na moim pudełku i działa, nawet z wieloma --exclude=w tej samej linii. Różnica musi być więc idiotyczna /*, którą dołączyłem do każdego podkatalogu. Przetestuję to dziś wieczorem w skrypcie produkcyjnym i zdam raport. Kolejny +1.
ateiob

Dla mnie odpowiedź od @carlo była szczególnym problemem - głupia smoła nie może przyjąć - wyklucz jako ostatnia opcja w linii poleceń - oczywiście powodując wiele bólów głowy. Dziękuje wszystkim.
moodboom

32

Być może twoja wersja tarwymaga, aby --excludeopcje musiały być umieszczone na początku tarpolecenia.

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

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

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

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

Alternatywny:

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

Oto kolejna tarwskazówka polecenia :

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

Zobacz moją aktualizację powyżej. Ostatnia wypróbowana odmiana (bez cudzysłowów, pojedyncza spacja) działa. Nie mam pojęcia dlaczego. +1 za przemyślaną odpowiedź + linki.
ateiob

Do twojej wiadomości, w debianie, jeśli nie precyzuję filtra, --exclude=mydir/*to znaczy, że to nie działa (używa tar --exclude=maindir/mydir/* -cjf archive.tar2.bz2 maindir/*).
Olivier Pons,

1
@OlivierPons zamiast „pod debianem”, a może wraz z nim, umieść wersję tar ( tar --version); Debian będzie prawdopodobnie dostarczany z wieloma różnymi wersjami smoły przez lata.
msouth

1
Moja wersja (1.29) działa tylko --excludewcześniej -czf.
falsePockets

8

Aby wykluczyć wiele plików, spróbuj

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

Pozwoli to zaoszczędzić trochę kodu i bólu głowy. Jest to globalne rozwiązanie dla wszystkich rodzajów programów / opcji. Jeśli chcesz również uwzględnić katalog nadrzędny w swoim wyborze (w tym przypadku dane), musisz dołączyć przecinek końcowy. Na przykład:

umount /data/{sub1,sub2,}

3
Uwielbiam curlies. Uważam, że wiele osób nie wie o nich, nawet po latach doświadczenia w Uniksie. mv /very/very/very/very/long/path/to/a/file{,.bak}
msouth

5

Ten link może być pomocny. http://answers.google.com/answers/threadview/id/739467.html

Dwie bezpośrednie różnice między niedziałającą linią a kilkoma wskazówkami w linku:

  1. Wszystkie wykluczenia pojawiają się po katalogu najwyższego poziomu.
  2. Nie może mieć żadnych spacji po ostatnim --exclude.

Dzięki. Odpowiedź -MAKprzykuła moją uwagę i do tej pory udało mi się zauważyć następujące różnice między moją niedziałającą linią a następującymi: 1. Wszystkie wykluczenia pojawiają się po katalogu najwyższego poziomu. 2. Nie może zawierać żadnych spacji po ostatnim --exclude. Przetestuję te spostrzeżenia i zdam relację. Na razie +1.
ateiob

@ateiob Jeśli to wymyślisz, czy możesz opublikować odpowiedź tutaj lub ją edytować? Na ogół wolimy nie mieć odpowiedzi, które są tylko linkami w innym miejscu
Michael Mrozek

@Michael Mrozek Absolutnie. To jest dokładnie to, co napisałem w moim komentarzu. :)
ateiob

3

Obejściem może być użycie kombinacji find ... -prunei tarwykluczenie określonych katalogów.

W systemie Mac OS X wydaje się, że --excludeopcja GNU tardziała tak, jak powinna.

W poniższym przypadku testowym katalogi /private/var/log/asli /private/var/log/DiagnosticMessagesmają zostać wykluczone ze skompresowanego archiwum /private/var/logkatalogu.

# 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

Dzięki +1 za sugestię. W tym momencie wciąż próbuję zrozumieć, dlaczego dobrze udokumentowana (i dojrzała) funkcja nie działa w moim skrypcie, co noc prowadzonym przez crona.
ateiob

3

Być może możesz wypróbować polecenie z inną opcją:

--wildcards

I sprawdź, czy działa zgodnie z przeznaczeniem.


Zobacz moją aktualizację powyżej. Ostatnia wypróbowana odmiana (bez cudzysłowów, pojedyncza spacja) działa. Nie mam pojęcia dlaczego. +1 za pomysł.
ateiob

3

Korzystam z komputera Mac i okazało się, że wykluczenia nie działały, chyba że folder najwyższego poziomu jest ostatnim argumentem

przykład działającego polecenia:

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

FYI:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3

To samo dotyczy tar 1.27.1 przez Ubuntu 14.04.
Greg Bell

3

W moim przypadku nie wykluczało to z innego powodu.

Pełna ścieżka vs ścieżka względna.

Zarówno wykluczenie, jak i katalog muszą używać tego samego formatu ścieżki (tj. Zarówno pełna ścieżka, jak i obie ścieżki względne)

Przykład:

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

To nie zadziała, ponieważ exclude używa pełnej ścieżki, gdzie jako cel używa ścieżki względnej

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

Działa to, ponieważ oba używają pełnej ścieżki

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

Działa to, ponieważ oba używają ścieżki względnej



1

Dodatkowe uwagi do doskonałej odpowiedzi R. Perrina :

Załóżmy, że nie chcesz archiwizować ścieżek bezwzględnych, ale względnych, np. „Dane” zamiast „/ tmp / data”. Aby wykluczyć ścieżki bezwzględne, argumenty tar będą się różnić w zależności od implementacji tar (tar gnu vs. tar bsd), którego używasz:

$ 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

Właśnie wykryto na tar (GNU tar) 1.29

To wywołanie nie wyklucza z plików archiwów określonych parametrem --exclude-from:

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

To połączenie działa poprawnie:

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

Kolejność parametrów jest ważna!


0

Próbowałem różnych kombinacji, w tym kilku wymienionych odpowiedzi, i po prostu nie mogłem wykluczyć wymienionych plików.

Mając dość gonienia za odpowiedzią na to, co miało być pięciominutową pracą, zrobiłem coś przeciwnego: stworzyłem archiwum folderów, które chciałem dołączyć.

Zrobiłem to, tworząc archiwum, a następnie dodając do niego :

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

Kilka uwag:

  • Użyłem ścieżki względnej zamiast ścieżek bezwzględnych (które również sprawiały kłopoty), uruchamiając z katalogu głównego systemu plików.
  • Musisz utworzyć zwykłe tar(a nie spakowane archiwum tar .tgz/ .tar.gz) archiwum - możesz je później skompresować za pomocągzip mybackup.tar
  • Upewnij się, że nie umieścisz archiwum w żadnym folderze, który dołączasz, w przeciwnym razie dostaniesz rekurencję (częściowa kopia zapasowa również znajduje się w samej kopii zapasowej).
  • Zwróć uwagę na różnicę w pierwszym poleceniu (utwórz) od innych (dodaj).
  • Możesz sprawdzić, czy pliki są dodawane, a nie zastępować kopię zapasową (np. Po drugim poleceniu), jeśli jesteś paranoikiem, używając tar tvf mybackup.tar.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.