Como combinar o comando 'tar' com 'find'

23

O comando find fornece esta saída:

[root@localhost /]# find var/log/ -iname anaconda.*
var/log/anaconda.log
var/log/anaconda.xlog
var/log/anaconda.yum.log
var/log/anaconda.syslog
var/log/anaconda.program.log
var/log/anaconda.storage.log

Depois de combinar com o tar, ele mostra essa saída:

[root@localhost /]# find var/log/ -iname anaconda.* -exec tar -cvf file.tar {} \;
var/log/anaconda.log
var/log/anaconda.xlog
var/log/anaconda.yum.log
var/log/anaconda.syslog
var/log/anaconda.program.log
var/log/anaconda.storage.log

Mas ao listar o arquivo tar, ele mostra apenas um único arquivo

[root@localhost /]# tar -tvf file.tar
-rw------- root/root    208454 2012-02-27 12:01 var/log/anaconda.storage.log

O que estou fazendo de errado aqui?

Com xargs estou recebendo esta saída:

[root@localhost /]# find var/log/ -iname anaconda.* | xargs tar -cvf file1.tar

Segunda pergunta

Enquanto digita / na frente do var, significa find /var/log o que está dando esta tabelaage tar: Removendo o início '/' dos nomes dos membros

[root@localhost /]# find /var/log/ -iname anaconda.* -exec tar -cvf file.tar {} \;
tar: Removing leading '/' from member names
/var/log/anaconda.log
tar: Removing leading '/' from member names
/var/log/anaconda.xlog
tar: Removing leading '/' from member names
/var/log/anaconda.yum.log
tar: Removing leading '/' from member names
/var/log/anaconda.syslog
tar: Removing leading '/' from member names
/var/log/anaconda.program.log
tar: Removing leading '/' from member names
/var/log/anaconda.storage.log

De uma forma simples, qual é a diferença entre os dois seguintes?

find var/log e find /var/log

    
por max 01.12.2012 / 15:23

6 respostas

34

Observe que find chamará a ação -exec para todos os arquivos que encontrar.

Se você executar tar -cvf file.tar {} para cada arquivo find outputs, isso significa que você sobrescreverá file.tar todas as vezes, o que explica por que você acaba com um arquivo que contém apenas anaconda.storage.log - é o último arquivo find saídas.

Agora, você realmente deseja anexar os arquivos ao arquivo, em vez de criá-lo toda vez (isso é o que a opção -c faz). Então, use o seguinte:

find var/log/ -iname "anaconda.*" -exec tar -rvf file.tar {} \;

A opção -r é anexada ao arquivo, em vez de ser recriada sempre.

Observação: Substitua -iname anaconda.* por -iname "anaconda.*" . O asterisco é um curinga e pode ser expandido pelo seu shell antes que find o veja. Para evitar essa expansão, coloque o argumento entre aspas duplas.

Quanto a tar remover o líder / : O arquivo deve conter apenas nomes de arquivos relativos . Se você adicionasse arquivos com um / inicial, eles seriam armazenados como nomes de arquivos absolutos /var/… no seu computador, por exemplo.

IIRC isto é simplesmente uma precaução para tar implementações além do GNU, e é mais seguro desta forma porque você não sobrescreverá seus dados reais em /var/… quando você extrair o arquivo se ele contiver nomes de arquivos relativos.

    
por 01.12.2012 / 15:40
32

Você pode usar algo como:

find var/log -iname 'anaconda.*' -print0 | tar -cvf somefile.tar --null -T -

Os -print0 e -T trabalham juntos para permitir nomes de arquivos com espaços newlines, etc. O% final - diz ao tar para ler os nomes dos arquivos de entrada de stdin.

Observe que -print0 deve vir no final do seu extrato, por esta resposta . Caso contrário, você provavelmente obterá mais arquivos do que o esperado.

    
por 01.12.2012 / 16:10
11

Tente isto:

tar -cvf file.tar 'find var/log/ -iname "anaconda.*"'

Você estava tentando usar find to -exec tar . Mas a maneira como a opção -exec funciona, ele executa esse comando uma vez para cada arquivo correspondente que encontrar, fazendo com que tar sobrescreva o arquivo tar que ele produz toda vez. É por isso que você acabou apenas com o último. Além disso, você precisa colocar aspas ao redor do padrão especificado para find , para que o shell não o expanda antes de passá-lo para find .

Usando a substituição de comandos com backticks (ou usando $(...) notação, se preferir), toda a lista de nomes produzidos por find é colada na linha de comando como argumentos para tar , fazendo com que ela grave todos eles de uma vez.

    
por 01.12.2012 / 15:40
6

Pergunta 1

Seu comando falha porque tar está pegando cada um dos arquivos encontrados e arquivando-os em file.tar . Toda vez que isso acontece, ele sobrescreve o file.tar criado anteriormente.

Se o que você quer é um arquivo com todos os arquivos, simplesmente execute tar diretamente, não há necessidade de find (e sim, isso funciona para arquivos com espaços em seus nomes):

tar -vcf file.tar /var/log/anaconda*   

Questão 2

Os dois comandos são completamente diferentes:

  • localizar var / log pesquisará um diretório chamado var/log que é um subdiretório do diretório atual , é equivalente a find ./var/log (observe o ./ ).

  • localizar / var / log pesquisará um diretório chamado /var/log que é um subdiretório da raiz, / .

A mensagem principal / é de tar , não find . Isso significa que ele está removendo o primeiro / de seus nomes de arquivos para criar caminhos absolutos em relativos . Isso significa que o arquivo de /var/log/anaconda.error será extraído para ./var/log/anaconda.error quando você descompactar o arquivo.

    
por 01.12.2012 / 15:44
1

Existem duas maneiras em que -exec pode funcionar. Uma maneira executa o comando várias vezes - uma vez para cada arquivo; o outro caminho executa o comando uma vez, incluindo todos os arquivos como uma lista de parâmetros.

  • -exec tar -cvf file.tar {} ';' executa o comando tar para cada arquivo, sobrescrevendo o archive a cada vez.
  • -exec tar -cvf file.tar {} '+' executa o comando tar uma vez, criando um arquivo de todos os arquivos encontrados.
por 11.07.2017 / 10:34
1

Eu acho que usar -exec para cada arquivo pode tornar a compactação de tar muito lenta, se você tiver muitos arquivos. Eu prefiro usar o comando:

find . -iname "*.jpg" | cpio -ov -H tar -F jpgs.tar
    
por 27.07.2017 / 18:10