Inspecter et extraire des archives ZIP avec unzip
Utilisez unzip -l pour inspecter un ZIP, unzip -t pour vérifier ses données compressées et unzip -n pour extraire
sans remplacer les fichiers existants. Pour un répertoire de paquets téléchargés, il vous faut aussi
un script de traitement par lots qui signale les échecs même lorsqu’une archive traitée ensuite
réussit. Ce guide vous fournit à la fois une petite archive d’entraînement et un script qui conserve
chaque paquet dans son propre répertoire de sortie.
Vérifier vos outils
Utilisez Linux avec Bash, Info-ZIP UnZip et les utilitaires habituels cp, mkdir, mktemp et rm. Il vous
faut aussi Info-ZIP Zip pour créer l’archive d’entraînement. Ces exemples ont été testés avec
Bash 5.3.15, UnZip 6.00 et Zip 3.0 ; utilisez les paquets maintenus par votre distribution. Vérifiez
les implémentations avec :
bash --version && unzip -v && zip -v
Le manuel cité ci-dessous concerne Info-ZIP : un autre programme nommé unzip peut donc se comporter
différemment. unzip -v affiche aussi UNZIP et UNZIPOPT, des variables d’environnement qui peuvent ajouter des
options par défaut. Les commandes individuelles ci-dessous supposent que ces variables ne sont pas
définies ; le script de traitement par lots les efface dans son propre processus.
Travaillez avec des fichiers ZIP fiables et non chiffrés, comme des paquets provenant d’un éditeur
que vous avez vérifié. -t vérifie les valeurs CRC stockées dans l’archive ; il n’authentifie pas son
éditeur et ne garantit pas que son contenu est sûr. Un répertoire d’extraction n’est pas un bac à
sable pour les fichiers téléversés par les utilisateurs. Les archives non fiables nécessitent un
processus de travail isolé et des limites de ressources que ce flux de travail ne fournit pas.
Inspecter un ZIP avant l’extraction
Collez ceci dans Bash pour créer unzip-demo sous votre répertoire courant. Si ce nom existe déjà, la
préparation s’arrête sans modifier son contenu. Les parenthèses maintiennent votre shell dans son
répertoire d’origine.
(
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
)
Depuis le même répertoire de départ, listez les entrées, puis vérifiez leurs données :
unzip -l ./unzip-demo/downloads/package.zip &&
unzip -t ./unzip-demo/downloads/package.zip
La liste inclut config.json et build.log ; le test ne devrait signaler aucune erreur. D’après le
manuel Info-ZIP, -l lit la liste, tandis que -t décompresse les entrées en mémoire
et compare leurs CRC. Une liste réussie ne prouve pas à elle seule que les données peuvent être
extraites.
Extrayez les deux entrées dans un répertoire distinct :
unzip -n ./unzip-demo/downloads/package.zip -d ./unzip-demo/extracted
Vous devriez maintenant avoir unzip-demo/extracted/config.json et unzip-demo/extracted/build.log.
-n ignore un fichier existant sans rien demander. Lors d’une nouvelle exécution, cela signifie qu’un
config.json modifié localement reste modifié, même si la commande renvoie zéro. N’utilisez -o que si vous
avez l’intention de remplacer des fichiers existants ; cette option supprime les demandes de
confirmation d’écrasement en autorisant le remplacement.
Extraire uniquement ce dont vous avez besoin
Passez un motif de membres entre guillemets pour sélectionner les fichiers JSON :
unzip -n ./unzip-demo/downloads/package.zip '*.json' -d ./unzip-demo/config-only
Cela crée config-only/config.json sans extraire build.log, et conserve les fichiers existants lors des
nouvelles exécutions. Les guillemets empêchent Bash de développer *.json par rapport à votre répertoire
de travail ; UnZip applique le motif aux membres de l’archive. Pour les exclusions, -x '*.log' omet les
entrées de journal correspondantes. Pour inspecter uniquement la configuration sans créer de fichier,
utilisez unzip -p ./unzip-demo/downloads/package.zip config.json.
Traiter un répertoire sans masquer les échecs
Pour le traitement par lots, appliquez une politique de sortie plus stricte : une destination par
archive déjà existante constitue un échec, et non une demande de fusion des fichiers. Enregistrez le
contenu suivant sous extract-zips.sh dans votre répertoire de départ, puis exécutez-le avec bash comme
indiqué ci-dessous. Ne le chargez pas dans votre shell avec la commande source.
Le script traite les fichiers ordinaires non masqués de premier niveau dont le nom se termine par
.zip en minuscules ; il ignore les liens symboliques et les répertoires. Ne modifiez pas les fichiers
d’entrée pendant l’exécution et n’attribuez la racine de sortie qu’à une seule invocation à la fois.
Le script a besoin d’espace pour les fichiers extraits et pour une copie temporaire du plus gros 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"
Exécutez le script enregistré sur l’archive d’entraînement :
bash ./extract-zips.sh ./unzip-demo/downloads ./unzip-demo/batch-output
Une première exécution réussie affiche une ligne Extracted: et crée batch-output/package/config.json
et batch-output/package/build.log. Une deuxième exécution renvoie 1 et laisse ce répertoire intact.
Choisissez une nouvelle racine de sortie lorsque vous voulez une nouvelle extraction.
La copie temporaire donne à UnZip un nom input.zip littéral. C’est important pour des noms comme
release[1].zip : les guillemets du shell ne suffisent pas à désactiver la correspondance de caractères
génériques propre à UnZip pour les archives. Le nom source détermine toujours la destination. Les
chemins sont résolus une seule fois avec cd -P et capturés depuis $PWD, de sorte que la découverte et
l’extraction utilisent le même répertoire physique sans perdre les sauts de ligne finaux dans les
noms de répertoires.
Chaque ZIP doit réussir -t avant que sa destination soit créée. -o s’applique ensuite uniquement
dans ce répertoire nouvellement créé, et -P '' fournit un mot de passe vide afin qu’aucune demande
interactive de mot de passe n’ait lieu. Les paquets protégés par mot de passe nécessitent un flux de
travail distinct. Le script poursuit le traitement après un échec, mais ne remet jamais status à
zéro. Les
règles de Bash sur les sous-shells et les processus
empêchent les changements de répertoire et les options du script enregistré d’affecter le shell
appelant.
Agir selon le résultat
Le script de traitement par lots renvoie 0 uniquement s’il a trouvé au moins une archive éligible
et que chaque archive s’est terminée sans avertissement ni erreur. Il renvoie 1 en cas de
destination existante, d’absence d’entrée éligible, ou d’échec de copie, de validation ou
d’extraction ; 2 signifie que les arguments sont incorrects. Un succès ultérieur ne peut pas
masquer un échec antérieur.
Conservez les diagnostics d’UnZip lorsque vous analysez un échec. Un statut de sortie d’UnZip non nul peut indiquer des données endommagées, une compression ou un chiffrement non pris en charge, ou un problème de système de fichiers. Qualifier tous ces cas de « corruption » vous ferait chercher au mauvais endroit.
Une vérification des données échouée ne crée aucune destination par archive. Un échec pendant l’extraction peut laisser des fichiers partiels ; inspectez-les avant de réessayer dans une nouvelle racine de sortie. Les sorties déjà terminées et les ZIP d’origine restent en place. Le script supprime uniquement sa copie temporaire privée.
Pour une tâche de build, laissez le statut non nul du script arrêter le traitement en aval. Pour une nouvelle exécution manuelle, choisissez une nouvelle racine de sortie ou inspectez d’abord les fichiers existants. Cette décision relève de votre flux de travail, et non d’une demande d’écrasement sans surveillance.
