Comme l'a dit Mathias, unzip
n'a pas une telle option, mais un bash script en une ligne peut faire le travail.
Le problème est que la meilleure approche dépend de la disposition de vos archives. Une solution qui suppose que un seul répertoire de premier niveau échouera lamentablement si le contenu se trouve directement à la racine de l'archive (pensez à /a/foo
/b/foo
/foo
et le chaos du déshabillage /a
y /b
).
Et le même échec se produit avec tar --strip-component
. Il n'existe pas de solution unique.
Donc, pour dépouiller le répertoire racine, en supposant qu'il y a est un (et seulement un) :
unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"
Assurez-vous simplement que les fichiers/répertoires de second niveau no ont le même nom que le parent de premier niveau (par exemple, /foo/foo
). Mais /foo/bar/foo
y /foo/bar/bar
sont bien. Si c'est le cas, ou si vous voulez juste être sûr, vous pouvez utiliser un disque provisoire pour l'extraction :
temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"
Si vous utilisez Bash, vous pouvez tester si le niveau supérieur est un répertoire unique ou non en utilisant :
f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"
En parlant de Bash, vous devriez activer dotglob
pour inclure les fichiers cachés, et vous pouvez tout regrouper dans une seule et même fonction très pratique :
# unzip featuring an enhanced version of tar's --strip-components=1
# Usage: unzip-strip ARCHIVE [DESTDIR] [EXTRA_cp_OPTIONS]
# Derive DESTDIR to current dir and archive filename or toplevel dir
unzip-strip() (
set -eu
local archive=$1
local destdir=${2:-}
shift; shift || :
local tmpdir=$(mktemp -d)
trap 'rm -rf -- "$tmpdir"' EXIT
unzip -qd "$tmpdir" -- "$archive"
shopt -s dotglob
local files=("$tmpdir"/*) name i=1
if (( ${#files[@]} == 1 )) && [[ -d "${files[0]}" ]]; then
name=$(basename "${files[0]}")
files=("$tmpdir"/*/*)
else
name=$(basename "$archive"); name=${archive%.*}
files=("$tmpdir"/*)
fi
if [[ -z "$destdir" ]]; then
destdir=./"$name"
fi
while [[ -f "$destdir" ]]; do destdir=${destdir}-$((i++)); done
mkdir -p "$destdir"
cp -ar "$@" -t "$destdir" -- "${files[@]}"
)
Maintenant, mettez ça dans votre ~/.bashrc
et vous n'aurez plus jamais à vous en soucier. A utiliser simplement comme :
unzip-strip sourcefile.zip [mysubfolder] [OPTIONS]
Cette petite bête le fera :
- Créer
mysubfolder
pour vous s'il n'existe pas
- Détectez automatiquement si votre archive zip contient un seul répertoire de premier niveau et gérez l'extraction en conséquence.
-
mysubfolder
es en option . S'il est vide, il sera extrait dans un sous-répertoire du répertoire actuel (pas nécessairement le répertoire archives répertoire !), dont le nom a été donné :
- Le seul répertoire de premier niveau dans l'archive, s'il y en a un.
- ou le nom du fichier d'archive, sans le (vraisemblablement
.zip
) extension
- Si le chemin de destination, donné ou dérivé, existe déjà en tant que fichier incrémente le nom jusqu'à ce qu'un nom approprié soit trouvé (nouveau chemin ou répertoire existant).
- Par défaut :
- être silencieux
- écraser tout fichier existant
- préserver les liens et les attributs (mode, horodatage, etc.)
- Pass extra
OPTIONS
a cp
. Les options utiles sont :
-
-v|--verbose
: sortir chaque fichier copié, tout comme unzip
fait
-
-n|--no-clobber
: ne pas écraser les fichiers existants
-
-u|--update
: n'écrase que les fichiers qui sont plus récents que la destination
- Exiger un supplément
OPTIONS
à partir du 3ème argument. Créez un analyseur d'arguments approprié si nécessaire.
- Utilisez double l'espace disque extrait pendant l'opération, en raison de l'approche "extraire dans le répertoire temporaire et copier". Il n'y a aucun moyen de contourner ce problème sans perdre une partie de sa flexibilité et de ses fonctionnalités.