tar --exclude não exclui. Por quê?

60

Eu tenho esta linha muito simples em um script bash que é executado com sucesso (ou seja, produzindo o arquivo _data.tar ), exceto que não exclui os subdiretórios que é dito excluir através do --exclude option:

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

Em vez disso, ele produz um arquivo _data.tar que contém tudo sob / data, incluindo os arquivos nos subdiretórios que eu queria excluir.

Alguma ideia do porquê? e como consertar isso?

Atualizar Eu implementei minhas observações com base no link fornecido na primeira resposta abaixo (dir de nível superior primeiro, sem espaço em branco após a última exclusão):

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

Mas isso não ajudou. Todos os subdiretórios "excluídos" estão presentes no arquivo _data.tar resultante.

Isso é intrigante. Se isso é um bug no tar atual (GNU tar 1.23, em um CentOS 6.2, Linux 2.6.32) ou "extrema sensibilidade" de tar para espaços em branco e outros erros de digitação fáceis de serem interpretados, considero isso um bug. Por enquanto.

Isso é horrível : tentei o insight sugerido abaixo (sem trailing /* ) e ainda não funciona no script de produção:

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

Eu não vejo nenhuma diferença entre o que eu tentei e o que @Richard Perrin tentou, exceto pelas aspas e 2 espaços ao invés de 1. Eu vou tentar isto (devo esperar pelo script noturno para rodar como o diretório para fazer backup é enorme) e reportar de volta.

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

Estou começando a pensar que todas essas tar --exclude de sensibilidades não são do tar, mas algo no meu ambiente, mas o que poderia ser isso?

Funcionou! A última variação tentou (sem espaço entre aspas simples e espaço único em vez de espaço duplo entre o --exclude s) testado. Estranho, mas aceitando.

Inacreditável! Acontece que uma versão mais antiga de tar (1.15.1) só seria excluída se o diretório de nível superior fosse last na linha de comando . Isso é exatamente o oposto de como a versão 1.23 exige. FYI.

    
por ateiob 27.02.2012 / 16:47

12 respostas

42

Se você quiser excluir um diretório inteiro, seu padrão deve corresponder a esse diretório, não aos arquivos dentro dele. Use --exclude=/data/sub1 em vez de --exclude='/data/sub1/*'

Tenha cuidado ao citar os padrões para protegê-los da expansão do shell.

Veja este exemplo, com problemas na chamada 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
    
por 29.02.2012 / 06:17
22

Pode ser que sua versão de tar exija que as opções --exclude tenham que ser colocadas no início do comando tar .

Veja: link

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

Veja: link

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

No entanto, outra dica de comando tar é de aqui :

tar cvfz myproject.tgz --exclude='path/dir_to_exclude1' \
                       --exclude='path/dir_to_exclude2' myproject
    
por 03.03.2012 / 16:50
7

Para excluir vários arquivos, tente

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

Isso salvará algum código e dor de cabeça. Esta é uma solução global, para todos os tipos de programas / opções. Se você também quiser incluir o diretório pai em sua seleção (neste caso, dados), você deve incluir uma vírgula final. Por exemplo:

umount /data/{sub1,sub2,}
    
por 06.06.2013 / 09:27
5

Esse link pode ser útil. link

Duas diferenças imediatas entre a linha que não funciona e algumas dicas no link:

  1. Todas as exclusões vêm após o diretório de nível superior.
  2. Não pode ter NENHUM espaço após o último --exclude .
por 27.02.2012 / 17:04
3

Uma solução alternativa pode ser usar uma combinação de find ... -prune e tar para excluir os diretórios especificados.

No Mac OS X, a opção --exclude do GNU tar parece funcionar como deveria.

No caso de teste a seguir, os diretórios /private/var/log/asl e /private/var/log/DiagnosticMessages devem ser excluídos de um arquivo compactado do diretório /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
    
por 01.03.2012 / 18:31
3

Talvez você possa tentar o comando com outra opção:

--wildcards

E verifique se está funcionando conforme o esperado.

    
por 03.03.2012 / 17:16
2

Estou usando um mac e descobri que as exclusões não estavam funcionando, a menos que a pasta de nível superior seja o último argumento

exemplo de comando de trabalho:

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

FYI:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3
    
por 19.08.2015 / 19:21
2

No meu caso, não foi excluído por um motivo diferente.

Caminho completo vs caminho relativo.

Tanto a exclusão quanto o diretório devem usar o mesmo formato de caminho (ou seja, caminho completo ou ambos os caminhos relativos)

Exemplo:

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

Isso não funcionará porque a exclusão usa o caminho completo onde o destino usa um caminho relativo

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

Isso funciona porque ambos usam o caminho completo

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

Isso funciona porque ambos usam o caminho relativo

    
por 01.07.2016 / 18:22
1

Em vez de --exclude= use -X com um arquivo de texto:

link

    
por 17.11.2015 / 07:11
1

Notas adicionais para A excelente resposta de R Perrin :

Suponha que você não queira arquivar caminhos absolutos, mas relativos, por exemplo 'data' em vez de '/ tmp / data'. Para excluir caminhos absolutos, seus argumentos tar serão diferentes com base na implementação do tar (gnu tar vs. bsd tar) usada:

$ 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
    
por 25.11.2016 / 09:26
0

Eu tentei todos os tipos de combinações, incluindo algumas das respostas listadas e não consegui excluir os arquivos listados.

Então, estando cansado de buscar a resposta para o que deveria ser um trabalho de cinco minutos, fiz o oposto: criei um arquivo das pastas que eu queria incluir.

Eu fiz isso criando um arquivo, em seguida, adicionando a ele :

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

Algumas notas:

  • Eu usei os caminhos relativos em vez de absolutos (que também estavam causando problemas) executando a partir da raiz do sistema de arquivos.
  • Você deve criar um arquivo tar (e não compactado com tar .tgz / .tar.gz ) simples - você pode compactar mais tarde usando gzip mybackup.tar
  • Certifique-se de não colocar o arquivo em qualquer pasta que você esteja incluindo ou você obterá alguma recursão (um backup parcial também incluído no próprio backup).
  • Anote a diferença no primeiro comando (criar) dos outros (adicionar).
  • Você pode verificar se os arquivos estão sendo adicionados em vez do backup substituído (por exemplo, após o segundo comando) se você estiver paranóico usando tar tvf mybackup.tar .
por 08.01.2018 / 00:33
0

Acabou de ser detectado no tar (GNU tar) 1.29

Esta chamada não exclui dos arquivos mortos especificados com --exclude-from:

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

Esta chamada funciona de forma coerente:

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

Ordem dos parâmetros é importante!

    
por 06.05.2018 / 12:01

Tags