web-dev-qa-db-fra.com

Équivalent à "--strip-components = 1" dans unzip?

J'ai un script qui extrait un fichier tar.gz dans un sous-répertoire spécifié mysubfolder :

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

Y a-t-il un moyen équivalent de faire cela avec un fichier Zip?

44
frigg

Comme Mathias l'a dit, unzip n'a pas cette option, mais un script bash à une ligne peut faire l'affaire.

Le problème est que la meilleure approche dépend de la disposition de vos archives. Une solution qui suppose un seul répertoire de premier niveau échouera misérablement si le contenu se trouve directement dans la racine de l’archive (pensez à /a/foo/b/foo/foo et au chaos de décapage /a et /b).

Et le même échec se produit avec tar --strip-component. Il n'y a pas de solution unique.

Donc, pour effacer le répertoire racine, en supposant que soit un (et seulement un):

unzip -d "$dest" "$Zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

Assurez-vous simplement que les fichiers/répertoires de deuxième niveau n'ont pas le même nom que le parent de niveau supérieur (par exemple, /foo/foo). Mais /foo/bar/foo et /foo/bar/bar sont ok. S'ils le font, ou si vous voulez simplement être en sécurité, vous pouvez utiliser un répertoire temporaire 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 seul répertoire ou non:

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 encapsuler dans une seule fonction pratique:

unzip-strip() (
    local Zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$Zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

Maintenant, mettez cela dans votre ~/.bashrc ou ~/.profile et vous n'aurez plus jamais à vous en soucier. Utilisez simplement comme:

unzip-strip sourcefile.Zip mysubfolder

(notez qu'il créera automatiquement mysubfolder s'il n'existe pas)

25
MestreLion

Je ne pouvais pas trouver une telle option dans les pages de manuel pour unzip , alors je crains que ce ne soit impossible. :(

Cependant, (selon la situation), vous pouvez contourner le problème. Par exemple, si vous êtes certain que le seul répertoire de niveau supérieur du fichier Zip est nommé foo- suivi d'un numéro de version, vous pouvez procéder comme suit:

cd /tmp
unzip /path/to/file.Zip
cd foo-*
cp -r . /path/to/destination/folder
3
Mathias Bynens

Vous pouvez utiliser -j pour les chemins d'accès indésirables (ne créez pas de répertoires).

0
Pedro Rodrigues