Xargs: altera o diretório de trabalho para o caminho do arquivo antes de executar?

3

Eu tenho uma pasta grande de arquivos RAR. Existe uma hierarquia significativa de níveis de pastas. Eu quero cancelar a coleção inteira de arquivos de uma só vez.

Eu tenho o seguinte one-liner, que funcionará:

find -name "*.rar" -print0 | xargs -0 -n 1 -P 4 unrar x

(Observe que estamos executando quatro threads em paralelo para acelerar a operação. :-))

O problema com esse comando é que o xargs é executado no diretório de nível superior para cada arquivo RAR. Isso significa que toda a saída está sendo despejada na pasta de nível superior.

Em vez disso, quero que a saída exista na mesma pasta que o arquivo RAR.

Exemplo:

Top level
 |--FolderA
 |----File1.rar
 |----File2.rar
 |--FolderB
 |----File1.rar
 |----File2.rar
 |----File3.rar
 |--FolderC
 |----File1.rar
 |----File2.rar

Cada um dos arquivos "File1.rar" contém um arquivo com o mesmo nome. Portanto, extraí-los todos na pasta de nível superior causa problemas de sobregravação.

Para resumir, eu quero extrair todos os arquivos RAR na hierarquia acima. Eu quero que o conteúdo de cada arquivo RAR exista na pasta em que o arquivo RAR existe.

Parece-me que a solução é de alguma forma definir o diretório de trabalho e, em seguida, execute o formulário de comando unrar lá. No entanto, desde que o comando find está me dando nomes de arquivos, não diretórios, eu não posso fazer algo como

| xargs -I{} -n 1 -P 4 cd {} \; unrar x {}

Falta escrever um script Perl ou Python que envolva o comando unrar e manipule a divisão do caminho fornecido em suas partes e a execução do comando. Existe uma maneira melhor de conseguir isso?

    
por fdmillion 25.03.2015 / 17:03

2 respostas

3

Existem comandos para extrair um nome de diretório ( dirname ) e nome de arquivo ( basename ) de um caminho. Então você poderia fazer algo como

find . -name '*.rar' -print0 | \
xargs -0 -I{} -n1 -P4 /bin/sh -c 'cd "$(dirname {})"; unrar x "$(basename {})"'

AFAIK, xargs não suporta a mudança de diretórios, então você precisaria de algum intermediário para fazer isso, daí o /bin/sh . Você mencionou escrever um wrapper em torno de unrar , e é basicamente isso que está sendo feito, exceto no formulário de uma linha.

    
por 25.03.2015 / 19:08
1

Usando o GNU Parallel, é assim:

find . -name '*.rar' | parallel cd {//} '&&' unrar x {/}

O GNU Parallel é um paralelizador geral e facilita a execução de trabalhos em paralelo na mesma máquina ou em várias máquinas para as quais você tem acesso ssh.

Se você tem 32 tarefas diferentes que você quer rodar em 4 CPUs, uma forma direta de paralelizar é rodar 8 tarefas em cada processador:

O

GNUParallelgeraumnovoprocessoquandoumtermina-mantendoasCPUsativaseeconomizandotempo:

Instalação

Se o GNU Parallel não for empacotado para sua distribuição, você pode fazer uma instalação pessoal, que não requer acesso root. Isso pode ser feito em 10 segundos ao fazer isso:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Para outras opções de instalação, consulte o link

Saiba mais

Veja mais exemplos: link

Assista aos vídeos de introdução: link

Percorra o tutorial: link

Inscreva-se na lista de e-mail para obter suporte: link

    
por 16.05.2015 / 22:39