Inspecionar e extrair arquivos ZIP com unzip
Use unzip -l para inspecionar um ZIP, unzip -t para verificar seus dados compactados e unzip -n para extrair
sem substituir arquivos existentes. Para um diretório de pacotes baixados, você também precisa de um
script em lote que reporte falhas mesmo quando um arquivo compactado posterior é processado com
sucesso. Este passo a passo oferece tanto um pequeno arquivo compactado de prática quanto um script
que mantém cada pacote em seu próprio diretório de saída.
Verificar as ferramentas
Use Linux com Bash, Info-ZIP UnZip e os utilitários habituais cp, mkdir, mktemp e rm. Você
também precisa do Info-ZIP Zip para criar o arquivo compactado de prática. Estes exemplos foram
testados com Bash 5.3.15, UnZip 6.00 e Zip 3.0; use os pacotes mantidos pela sua distribuição.
Verifique as implementações com:
bash --version && unzip -v && zip -v
O manual abaixo é do Info-ZIP, então um programa diferente chamado unzip pode se comportar de outra forma.
unzip -v também exibe UNZIP e UNZIPOPT, variáveis de ambiente que podem adicionar opções padrão.
Os comandos individuais abaixo pressupõem que essas variáveis não estão definidas; o script em lote
as limpa em seu próprio processo.
Trabalhe com arquivos ZIP confiáveis e não criptografados, como pacotes de um publicador que você
verificou. -t confere os valores de CRC armazenados no arquivo compactado; ele não autentica o publicador
nem comprova que o conteúdo é seguro. Um diretório de extração não é uma sandbox para uploads de
usuários. Arquivos compactados não confiáveis exigem um worker isolado e limites de recursos que vão
além deste fluxo de trabalho.
Inspecionar um ZIP antes de extrair
Cole isto no Bash para criar unzip-demo dentro do seu diretório atual. Se esse nome já
existir, a preparação para sem alterar o conteúdo dele. Os parênteses mantêm seu shell no diretório
original.
(
mkdir -- unzip-demo &&
cd -- unzip-demo &&
mkdir -- downloads &&
printf '{"mode":"development"}\n' > config.json &&
printf 'build complete\n' > build.log &&
zip -q ./downloads/package.zip config.json build.log
)
A partir do mesmo diretório inicial, liste as entradas e depois verifique os dados delas:
unzip -l ./unzip-demo/downloads/package.zip &&
unzip -t ./unzip-demo/downloads/package.zip
A listagem inclui config.json e build.log; o teste não deve reportar erros. De acordo com
o manual do Info-ZIP, -l lê a
listagem, enquanto -t descompacta as entradas na memória e compara seus CRCs. Uma listagem
bem-sucedida, por si só, não prova que os dados podem ser extraídos.
Extraia as duas entradas em um diretório separado:
unzip -n ./unzip-demo/downloads/package.zip -d ./unzip-demo/extracted
Agora você deve ter unzip-demo/extracted/config.json e unzip-demo/extracted/build.log.
-n ignora um arquivo existente sem perguntar. Em uma nova execução, isso significa que um
config.json editado localmente continua editado, mesmo que o comando retorne zero. Use -o apenas quando você
pretende substituir arquivos existentes; essa opção suprime as perguntas de sobrescrita ao permitir
a substituição.
Extrair apenas o que você precisa
Passe um padrão de membros entre aspas para selecionar arquivos JSON:
unzip -n ./unzip-demo/downloads/package.zip '*.json' -d ./unzip-demo/config-only
Isso cria config-only/config.json sem extrair build.log e mantém os arquivos existentes em
novas execuções. As aspas impedem que o Bash expanda *.json com base no seu diretório de trabalho; o
UnZip aplica o padrão aos membros do arquivo compactado. Para exclusões, -x '*.log' omite as entradas de
log correspondentes. Para inspecionar apenas a configuração sem criar um arquivo, use unzip -p ./unzip-demo/downloads/package.zip config.json.
Processar um diretório sem esconder falhas
Para trabalho em lote, use uma política de saída mais rígida: um destino já existente para um
arquivo compactado é uma falha, e não um pedido para mesclar arquivos. Salve o conteúdo a seguir
como extract-zips.sh no seu diretório inicial e execute-o com bash, como mostrado abaixo. Não use
source para carregá-lo no seu shell.
O script processa arquivos regulares, não ocultos e de nível superior terminados em .zip minúsculo;
ele ignora links simbólicos e diretórios. Mantenha os arquivos de entrada inalterados durante a
execução e use a raiz de saída em apenas uma invocação por vez. O script precisa de espaço para os
arquivos extraídos e para uma cópia temporária do maior ZIP.
#!/usr/bin/env bash
if (( $# != 2 )) || [[ -z $1 || -z $2 ]]; then
printf 'Usage: bash extract-zips.sh INPUT_DIR OUTPUT_DIR\n' >&2
exit 2
fi
unset UNZIP UNZIPOPT
input_dir=$1
output_dir=$2
[[ $input_dir = /* ]] || input_dir="$PWD/$input_dir"
[[ $output_dir = /* ]] || output_dir="$PWD/$output_dir"
cd -P -- "$input_dir" || exit 1
input_dir=$PWD
mkdir -p -- "$output_dir" || exit 1
cd -P -- "$output_dir" || exit 1
output_dir=$PWD
scratch=$(mktemp -d -- "$output_dir/.unzip.XXXXXXXX") || exit 1
trap 'rm -rf -- "$scratch"' EXIT
shopt -s nullglob
status=0
count=0
for archive in "$input_dir"/*.zip; do
[[ -f "$archive" && ! -L "$archive" ]] || continue
count=$((count + 1))
name=${archive##*/}
destination="$output_dir/${name%.zip}"
if [[ -e "$destination" || -L "$destination" ]]; then
printf 'Destination already exists: %s\n' "$destination" >&2
status=1
continue
fi
printf 'Checking: %s\n' "$archive"
# UnZip expands archive-name wildcards even inside a quoted shell argument.
if ! cp -f -- "$archive" "$scratch/input.zip" ||
! unzip -tq -P '' "$scratch/input.zip" </dev/null; then
printf 'Cannot copy or validate: %s\n' "$archive" >&2
status=1
continue
fi
if ! mkdir -- "$destination"; then
status=1
continue
fi
if unzip -qo -P '' "$scratch/input.zip" -d "$destination" </dev/null; then
printf 'Extracted: %s\n' "$destination"
else
printf 'Extraction failed; inspect partial output: %s\n' "$destination" >&2
status=1
fi
done
if (( count == 0 )); then
printf 'No regular .zip files found in: %s\n' "$input_dir" >&2
status=1
fi
exit "$status"
Execute o script salvo no arquivo compactado de prática:
bash ./extract-zips.sh ./unzip-demo/downloads ./unzip-demo/batch-output
Uma primeira execução bem-sucedida imprime uma linha Extracted: e cria batch-output/package/config.json
e batch-output/package/build.log. Uma segunda execução retorna 1 e deixa esse diretório intacto.
Escolha uma nova raiz de saída quando quiser uma extração do zero.
A cópia temporária dá ao UnZip um nome input.zip literal. Isso é importante para nomes como
release[1].zip: as aspas do shell, sozinhas, não desativam a correspondência de curingas que o próprio UnZip
aplica ao nome do arquivo compactado. O nome de origem continua determinando o destino. Os caminhos
são resolvidos uma única vez com cd -P e capturados a partir de $PWD, de modo que a descoberta e a
extração usam o mesmo diretório físico sem perder quebras de linha finais em nomes de diretórios.
Cada ZIP precisa passar em -t antes que seu destino seja criado. Depois disso, -o se aplica
apenas dentro desse diretório recém-criado, e -P '' fornece uma senha vazia para que não haja
solicitação interativa de senha. Pacotes protegidos por senha precisam de um fluxo de trabalho
separado. O script continua o processamento após uma falha, mas nunca redefine status para zero. As
regras de subshell e de processos
do Bash mantêm as mudanças de diretório e as opções do script salvo fora do shell que o chamou.
Agir com base no resultado
O script em lote retorna 0 somente quando encontrou pelo menos um arquivo compactado elegível e
todos os arquivos compactados foram concluídos sem aviso ou erro. Ele retorna 1 para um destino
já existente, para a ausência de entrada elegível ou para uma falha de cópia, validação ou extração;
2 significa que os argumentos estão errados. Um sucesso posterior não pode esconder uma falha
anterior.
Guarde os diagnósticos do UnZip ao investigar uma falha. Um status do UnZip diferente de zero pode indicar dados danificados, compressão ou criptografia sem suporte ou um problema no sistema de arquivos. Chamar tudo isso de “corrupção” faria você procurar no lugar errado.
Uma verificação de dados com falha não cria nenhum destino para o arquivo compactado. Uma falha durante a extração pode deixar arquivos parciais; inspecione-os antes de tentar novamente em uma nova raiz de saída. As saídas concluídas anteriormente e os ZIPs originais permanecem no lugar. O script remove apenas a própria cópia temporária privada.
Em uma tarefa de build, deixe o status diferente de zero do script interromper o processamento seguinte. Em uma nova execução manual, escolha uma nova raiz de saída ou inspecione primeiro os arquivos existentes. Essa decisão cabe ao seu fluxo de trabalho, e não a uma pergunta de sobrescrita sem supervisão.
