Encontre arquivos tar dentro de subdiretórios com script bash

1

Eu tenho um diretório que contém muitas pastas (> 5000):

folder1
folder2
folder3
...

Todas essas pastas têm muitos subdiretórios. Em um subdiretório específico de cada pasta, pode haver um arquivo tar.gz . Se uma pasta contiver um tar.gz archive, ele será apenas um, e estará em um subdiretório específico.

Por exemplo:

folder1/foo/baz.tar.gz
folder2/bar/qux.tar.gz
folder3 [no tar.gz file in this folder]
...

Eu preciso escrever um script bash para realizar o seguinte:

  • Eu quero percorrer cada pasta, encontrar o tar.gz archive, se existir, e descompactar seu conteúdo em um diretório diferente (que é o mesmo para todos os arquivos encontrados).
  • Quando todos os tar.gz archive forem encontrados, também preciso mover mais arquivos no mesmo diretório que o tar.gz archive, talvez seja necessário armazenar o caminho do archive.

Eu posso listar todos os arquivos com:

find . -name "*tar.gz"

Eu estou querendo saber se a manipulação do comando obtido é a solução mais ideal, ou o loop através de cada diretório seria melhor ...

Qual seria a abordagem mais ideal? Como deve ser realizado?

    
por tli 15.02.2018 / 11:56

2 respostas

1

Você pode executar basicamente qualquer operação ou lista de operações dentro da opção find -exec , então por que não untar de cada arquivo diretamente dentro de find -exec ? Para comandos complexos, é comum usar o recurso -exec para chamar um shell e usar a opção -c do comando shell para passar os comandos reais que você deseja executar. Por exemplo (na prática, há uma maneira muito mais simples de executar este exemplo real, mas é com o propósito de mostrar a ideia):

-exec sh -c 'mv "$1" "~/$1"' sh {} ';'

Isso iniciaria um shell para cada arquivo encontrado e faria com que ele movesse o arquivo para o diretório $HOME . Observe que o {} serve para passar o nome do arquivo encontrado como um parâmetro posicional do shell, isto é. $1 , portanto, no comando shell, $1 está sendo usado, não {} . No seu caso, uma solução desse tipo seria algo como:

-exec sh -c 'tar xvf "$1" -C "$(dirname $1)"' sh {} ';' 

A idéia é que esse idioma traz todos os recursos do seu shell favorito dentro do comando find . (E, sim, você poderia usar bash ou zsh em vez de sh , apenas saiba que sh é carregado muito mais rápido e quando você está processando muitos arquivos, isso pode aumentar).

Se isso é algo que você faz repetidamente, ou você espera de antemão que a operação vai demorar muito tempo, AND você tem uma CPU multi-core, então pode ser benéfico para você considere uma segunda opção - conecte sua lista de arquivos ao GNU parallel e execute a operação untar simultaneamente em todos os núcleos. Tente isso para começar:

find . -name "*tar.gz" -type f -print0 |
  parallel -0 tar xvf {} -C {//}

Como uma eficiência adicional, a resposta acima não precisa mais usar o comando dirname externo porque o GNU paralelo pode fazê-lo de maneira mais eficiente. Isso é o que o {//} está fazendo.

AVISO: Eu não sou especialista em parallel e estou oferecendo essa opção sem experiência real usando, por isso, se outras pessoas puderem conversar sobre se essa é a maneira correta, isso seria ótimo.

    
por 15.02.2018 / 12:24
0

Você poderia usar o comando find para passar os caminhos do tarball para um script que poderia descompactá-los (eu não testei isso):

$ cat script
#!/bin/bash --
tarball="${1}"
dir="$(dirname ${tarball})"
tar xvf "${tarball}" -C "${dir}"

Em seguida, chame o script com find:

$ find . -type f -name '*.tar.gz' -exec ./script "{}" \;

Ou em um comando de localização (testado rapidamente):

find . -type f -name '*.tar.gz' -exec sh -c 'dir="$(dirname ''"{}"'')"; tar xvf "{}" -C "${dir}"' \;
    
por 15.02.2018 / 12:28