Organize todos os PDFs em um diretório, mantendo a estrutura do diretório

11

Estou tentando criar um tarball compactado que contém todos os arquivos PDF existentes em um dos meus diretórios. A estrutura de diretórios precisa ser mantida. Diretórios vazios não são necessários, mas eu realmente não me importo se eles estão lá.

Por exemplo, digamos que eu tivesse um diretório parecido com este:

dir
dir/subdir1
dir/subdir1/subsubdir1/song.mp3
dir/subdir2
dir/subdir2/subsubdir1
dir/subdir2/subsubdir1/document.pdf
dir/subdir2/subsubdir1/another-song.mp3
dir/subdir2/subsubdir1/top-ten-movies.txt
dir/subdir3
dir/subdir3/another-document.pdf

Depois de executar o comando, gostaria de dir.tar.gzconter o seguinte:

dir
dir/subdir2
dir/subdir2/subsubdir1
dir/subdir2/subsubdir1/document.pdf
dir/subdir3
dir/subdir3/another-document.pdf

Possível?

Matt Alexander
fonte

Respostas:

10

Isso listará todos os PDFs:

$ find dir/ -name '*.pdf'
./dir/subdir2/subsubdir1/document.pdf
./dir/subdir3/another-document.pdf

Você pode canalizar isso para xargsobtê-lo como uma única linha delimitada por espaço e alimentá-lo tarpara criar o arquivo morto:

$ find dir/ -name '*.pdf' | xargs tar czf dir.tar.gz

(Dessa forma, omite os diretórios vazios)

Michael Mrozek
fonte
1
Isso é incrível, obrigado pela ajuda. Aqui está o que eu vim com:find docs \( -iname '*.pdf' -o -iname '*.mp3' \) -printf '"%p"\n' | xargs tar czf docs-media.tar.gz
Matt Alexander
3
@mattalexx: Este comando não funcionará se algum dos nomes de arquivo contiver espaços ou \'"(falha de xargs) e não funcionará se houver muitos nomes de arquivo (falha do kernel).
Gilles 'SO- stop be evil'
2
@Gilles Quanto aos nomes de arquivos com espaços e aspas simples, a -printf '"%p"\n'parte cuida disso (pelo menos para mim).
Matt Alexander
1
@ Gilles Interessante sobre a restrição do kernel. Quantos argumentos você pode ter em um comando no Linux?
Matt Alexander
5
Ah, no "não funcionará", observe que o modo de falha aqui é que, se a linha de comando for muito longa, o xargs a dividirá, de modo que a última chamada de tar substituirá silenciosamente os arquivos gravados por chamadas anteriores .
Gilles 'SO- stop be evil'
6

Com bash ≥4 ou zsh e GNU tar:

tar -czf dir.tar.gz dir/**/*.pdf

Isso pode não funcionar se você tiver um número muito grande de arquivos PDF e a linha de comando for muito longa. Então você precisaria de uma solução baseada em localização mais complexa (novamente, usando o GNU tar):

tar -cf dir.tar -T /dev/null
find dir -name '*.pdf' -exec tar -rf dir.tar {} +
gzip dir.tar

Como alternativa (e portabilidade), você pode criar o arquivo com pax .

pax -w -x ustar -s '/\.pdf$/&/' -s '/.*//' . | gzip >dir.tar.gz

O primeiro -sdiz para incluir todos os .pdfarquivos, sem alterar o nome. O segundo -sdiz para renomear todos os outros arquivos com um nome vazio, o que realmente significa não incluí-los no arquivo morto.

Gilles 'SO- parar de ser mau'
fonte
Ah, sim, eu quis mencionar zsh's **; Eu nem sabia que o bash 4 tinha isso agora
Michael Mrozek