Como você recursivamente arquivos descompactar em um diretório e seus subdiretórios a partir da linha de comando do Unix?
Pergunta
O comando unzip
não tem uma opção para recursivamente descompactar arquivos.
Se eu tiver a seguinte estrutura de diretórios e arquivos:
/Mother/Loving.zip /Scurvy/Sea Dogs.zip /Scurvy/Cures/Limes.zip
E eu quero para descompactar todos os arquivos em diretórios com o mesmo nome de cada arquivo:
/Mother/Loving/1.txt /Mother/Loving.zip /Scurvy/Sea Dogs/2.txt /Scurvy/Sea Dogs.zip /Scurvy/Cures/Limes/3.txt /Scurvy/Cures/Limes.zip
O comando ou comandos que eu iria emitir?
É importante que isso não engasgar com nomes de arquivos que têm espaços.
Solução
Se você deseja extrair os arquivos para a pasta respectiva você pode tentar este
find . -name "*.zip" | while read filename; do unzip -o -d "`dirname "$filename"`" "$filename"; done;
Uma versão multi-processados ??para sistemas que podem lidar com alta I / O:
find . -name "*.zip" | xargs -P 5 -I fileName sh -c 'unzip -o -d "$(dirname "fileName")/$(basename -s .zip "fileName")" "fileName"'
Outras dicas
Aqui está uma solução que envolve o comando find e um tempo loop:
find . -name "*.zip" | while read filename; do unzip -o -d "`basename -s .zip "$filename"`" "$filename"; done;
Uma solução que maneja bem todos os nomes de arquivo (incluindo novas linhas) e extratos em um diretório que está no mesmo local que o arquivo, apenas com a extensão removidos:
find . -name '*.zip' -exec sh -c 'unzip -o -d "${0%.*}" "$0"' '{}' ';'
Note que você pode facilmente torná-lo lidar com mais tipos de arquivos (como .jar
), adicionando-os usando -o
, por exemplo:.
find . '(' -name '*.zip' -o -name '*.jar' ')' -exec ...
Você pode usar encontrar junto com a bandeira -exec em uma única linha de comando para fazer o trabalho
find . -name "*.zip" -exec unzip {} \;
Algo como gunzip usando o sinalizador -r? ....
Viagens a estrutura de diretórios de forma recursiva. Se qualquer um dos nomes de arquivos especificados na linha de comando são diretórios, gzip descerá ao diretório e compactar todos os arquivos que ele encontra lá (ou descompactá-los no caso de gunzip).
Isso funciona perfeitamente como nós queremos:
descompactar arquivos:
find . -name "*.zip" | xargs -P 5 -I FILENAME sh -c 'unzip -o -d "$(dirname "FILENAME")" "FILENAME"'
comando Acima de não criar diretórios duplicados.
remover todos os arquivos zip:
find . -depth -name '*.zip' -exec rm {} \;
Se você estiver usando cygwin, a sintaxe é um pouco diferente para o comando basename.
find . -name "*.zip" | while read filename; do unzip -o -d "`basename "$filename" .zip`" "$filename"; done;
Sei que isso é muito antiga, mas foi um dos primeiros hits no Google, quando eu estava à procura de uma solução para algo semelhante, então eu vou postar o que eu fiz aqui. Meu cenário é um pouco diferente como eu basicamente só queria explodir completamente um frasco, juntamente com todos os frascos nela contido, então eu escrevi as seguintes funções festança:
function explode {
local target="$1"
echo "Exploding $target."
if [ -f "$target" ] ; then
explodeFile "$target"
elif [ -d "$target" ] ; then
while [ "$(find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)")" != "" ] ; do
find "$target" -type f -regextype posix-egrep -iregex ".*\.(zip|jar|ear|war|sar)" -exec bash -c 'source "<file-where-this-function-is-stored>" ; explode "{}"' \;
done
else
echo "Could not find $target."
fi
}
function explodeFile {
local target="$1"
echo "Exploding file $target."
mv "$target" "$target.tmp"
unzip -q "$target.tmp" -d "$target"
rm "$target.tmp"
}
Observe o <file-where-this-function-is-stored>
que é necessário se você está armazenando isso em um arquivo que não é lido por um shell não interativo, como aconteceu de eu estar. Se você está armazenando as funções em um arquivo carregado em cascas de não-interativas (por exemplo, .bashrc
creio eu) você pode deixar cair toda a declaração source
. Esperemos que isto irá ajudar alguém.
Um aviso pouco -. explodeFile
também exclui o arquivo ziped, você pode de mudança de curso que comentando a última linha
Outra solução interessante seria:
DESTINY=[Give the output that you intend]
# Don't forget to change from .ZIP to .zip.
# In my case the files were in .ZIP.
# The echo were for debug purpose.
find . -name "*.ZIP" | while read filename; do
ADDRESS=$filename
#echo "Address: $ADDRESS"
BASENAME=`basename $filename .ZIP`
#echo "Basename: $BASENAME"
unzip -d "$DESTINY$BASENAME" "$ADDRESS";
done;