Comment dé-décompresser, de-tar -xvf - désarchiver dans un dossier en désordre?

14

Habituellement, je désarchive les choses, $ mkdir newFolder; $ mv *.zip newFolder; $ cd newFolder; $unzip *.zipmais parfois je deviens paresseux et je le fais simplement dans un dossier arbitraire, de $ unzip *.zipsorte que de temps en temps je gâche avec d'autres contenus. Je vais énumérer ici quelques méthodes - certaines versions d'archives ont sûrement des drapeaux de merde tandis que d'autres plus spartiates, je suis plus intéressé par ces dernières.

Certaines façons de désarchiver, y en a-t-il d'autres?

  1. $ find . -anewer fileThatExistedBeforeUnarchieving -ok rm '{}' \;Les faiblesses sont qu'il répertorie les *.ziprépertoires, vous devez donc utiliser slow -ok, slow avec de nombreuses *.zipcorrespondances et, pour une raison quelconque, il ne semble pas correspondre à tout ce qui est extrait.

  2. S'il s'agit d'une petite quantité de fichiers extraits, un par un, lents, lourds et sujets aux erreurs.

  3. Lorsque je veux m'assurer que le contenu de l'archive est bien un dossier, je le vérifie parfois avec $ unzip -l *.bsd, fonctionne au moins dans la version unzip obsd.

Si vous faites référence à certains outils d'archivage, veuillez les indiquer le cas échéant. Restez simple cependant - je suis plus intéressé par les FAÇONS dont vous le faites, plutôt que par un seul outil.

Rui F Ribeiro
la source
1
Voir aussi Emplacement d'extrait accidentel - Comment nettoyer?
Gilles 'SO- arrête d'être méchant'
Voici un script que j'utilise pour automatiser les mkdir; unzipchoses, donc je ne suis jamais trop paresseux pour le faire! svn.mikelward.com/svn/scripts/untar
Mikel
2
Voir cette question et réponses connexes
alex

Réponses:

11

De nom

Vous pouvez générer la liste des fichiers dans l'archive et les supprimer, bien que cela soit fastidieusement fastidieux avec des archiveurs tels que décompresser ou 7z qui n'ont pas la possibilité de générer une liste simple de noms de fichiers. Même avec tar, cela suppose qu'il n'y a pas de nouvelle ligne dans les noms de fichiers.

tar tf foo.tar | while read -r file; do rm -- "$file" done
unzip -l foo.zip | awk '
    p && /^ --/ {p=2}
    p==1 {print substr($0, 29)}
    /^ --/ {++p}
' | while …
unzip -l foo.zip | tail -n +4 | head -n -2 | while …  # GNU coreutils only
7z l -slt foo.zip | sed -n 's/^Path = //p' | while …  # works on tar.*, zip, 7z and more

Au lieu de supprimer les fichiers, vous pouvez les déplacer vers leur destination prévue.

tar tf foo.tar | while read -r file; do
  if [ -d "$file" ]; then continue; fi
  mkdir -p "/intended/destination/${file%/*}"
  mv -- "$file" "/intended/destination/$file"
done

Utilisation de FUSE

Au lieu de dépendre d'outils externes, vous pouvez (sur la plupart des unités) utiliser FUSE pour manipuler des archives à l'aide de commandes de système de fichiers ordinaires.

Vous pouvez utiliser Fuse-zip pour jeter un œil à un zip, l'extraire avec cp, lister son contenu avec find, etc.

mkdir /tmp/foo.d
fuse-zip foo.zip /tmp/foo.d
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd /tmp/foo.d && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm /tmp/foo.d/**(:"s~/tmp/foo.d/~~"^/)
## Extract the contents where you really want them
cp -Rp /tmp/foo.d /intended/destination
fusermount -u foo.d
rmdir foo.d

AVFS crée une vue de l'ensemble de votre hiérarchie de répertoires où toutes les archives ont un répertoire associé (même nom avec # inséré à la fin) qui semble contenir le contenu de l'archive.

mountavfs
## Remove the files that were extracted mistakenly (GNU/BSD find)
(cd ~/.avfs/"$PWD/foo.zip#" && find . \! -type d -print0) | xargs -0 rm
## Remove the files that were extracted mistakenly (zsh)
rm ~/.avfs/$PWD/foo.zip\#/**/*(:"s~$HOME/.avfs/$PWD/foo.zip#~~"^/)
## Extract the contents where you really want them
cp -Rp ~/.avfs/"$PWD/foo.zip#" /intended/destination
umountavfs

Par date

En supposant qu'il n'y a pas eu d'autre activité dans la même hiérarchie que votre extraction, vous pouvez distinguer les fichiers extraits par leur heure de connexion récente . Si vous venez de créer ou de déplacer le fichier zip, vous pouvez l'utiliser comme coupure; sinon, utilisez ls -lctrpour déterminer une heure de coupure appropriée. Si vous voulez vous assurer de ne pas retirer les zips, il n'y a aucune raison de faire une approbation manuelle: findest parfaitement capable de les exclure. Voici des exemples de commandes utilisant zsh ou find; notez que les primaires -cminet -cnewerne sont pas en POSIX mais existent sur Linux (et d'autres systèmes avec GNU find), * BSD et OSX.

find . \! -name '*.zip' -type f -cmin -5 -exec rm {} +  # extracted <5 min ago
rm **/*~*.zip(.cm-6)  # zsh, extracted ≤5 min ago
find . -type f -cnewer foo.zip -exec rm {} +  # created or moved after foo.zip

Avec GNU find, FreeBSD et OSX, une autre façon de spécifier l'heure de coupure est de créer un fichier et de l'utiliser touchpour régler son mtime sur l'heure de coupure.

touch -d … cutoff
find . -type f -newercm cutoff -delete

Au lieu de supprimer les fichiers, vous pouvez les déplacer vers leur destination prévue. Voici un moyen avec GNU / * BSD / OSX find, en créant des répertoires dans la destination selon les besoins.

find . \! -name . -cmin -5 -type f -exec sh -c '
    for x; do
      mkdir -p "$0/${x%/*}"
      mv "$x" "$0/$x"
    done
  ' /intended/destination {} +

Équivalent Zsh (presque: celui-ci reproduit toute la hiérarchie des répertoires, pas seulement les répertoires qui contiendront les fichiers):

autoload zmv
mkdir -p ./**/*(/cm-3:s"|.|/intended/destination|")
zmv -Q '(**/)(*)(.cm-3)' /intended/destination/'$1$2'

Attention, je n'ai pas testé la plupart des commandes de cette réponse. Examinez toujours la liste des fichiers avant de les supprimer (exécutez d' echoabord, puis rmsi c'est ok).

Gilles 'SO- arrête d'être méchant'
la source
J'ai finalement rencontré ce problème aujourd'hui. En tant que root! En fin de compte, j'ai utilisé une combinaison de "Par nom" et "Par date"
phunehehe
1

Je me sens stupide, de toute façon je me suis gratté la tête pour écrire ce script quand j'ai eu un problème similaire. J'ai utilisé cpioavec le -itdrapeau pour obtenir une liste de fichiers; vous pouvez utiliser des commandes équivalentes pour d'autres archiveurs. La partie délicate est que l'archive cpio provient d'un initrd et que j'ai extrait dans /, de nombreux dossiers et fichiers ont le même nom que dans un système qui fonctionne. Heureusement, cpio n'a écrasé aucun de mes fichiers existants. J'utilise une vérification de l'heure pour m'assurer de ne rien supprimer qui existait avant la mauvaise commande.

#! /bin/sh

files=$(cpio -it < /mnt/temp/lglive.cpio)

for i in ${files}
do
    name=$(stat -c "%n" ${i})
    time=$(stat -c "%Y" ${i})
    # Time of the creation of the mess: 1296457595
    if [[ ${time} -gt 1296457590 && ${time} -lt 1296457600 ]]
    then
        if [[ -f ${name} ]]
        # If it is a file, it must have been created as part of the mess.
        then
            echo "rm ${name}"
        elif [[ -d ${name} ]]
        # If it is a directory, it may have been part of the mess
        # or maybe some files underneath it is created as part of the mess.
        then
            if [[ $(ls -A ${name}) ]]
            # If the directory contains something then don't delete it.
            then
                echo "${name} is not empty"
            # If the directory is empty then assume it is rubbish.
            else
                echo "rmdir ${name}"
            fi
        fi
    fi
done

echo "Files and directories still exist after the removal:"
for i in ${files}
do
    if [[ -e ${i} ]]
    then
        echo ${i}
    fi
done
phunehehe
la source
0

Que diriez-vous d'alimenter la liste des fichiers en archive xargs rm?

Ce serait tar -tf tarbomb.tar | xargs rmou unzip --list zipbomb.zip | xargs rm.

alex
la source
2
Les commandes telles qu'elles sont données ne fonctionneront pas dans le cas général, ce qui est dangereux car vous supprimez des fichiers. xargsattend son entrée citée d'une manière particulière qui findne produit pas. Utilisez xargs -I rm {}cette option pour que xargs traite plutôt un élément par ligne. Pour la commande unzip, quelle implémentation avez-vous? Le mien (Debian / Ubuntu) n'a pas --list, seulement -l, et il n'imprime pas seulement les noms de fichiers, de sorte qu'un traitement supplémentaire est nécessaire.
Gilles 'SO- arrête d'être méchant'
@ Gilles: 1) oui, c'est dangereux, mais puisque nous avons vraisemblablement écrasé les fichiers originaux - ils sont déjà partis. 2) Je ne parlais pas find. 3) vous avez raison unzip, je n'ai pas testé et il ne semble pas y avoir d'option pour une inscription non décorée. Non --listsur mon Ubuntu également - je n'ai tout simplement pas testé.
alex
Désolé pour la réponse en boîte, remplacer tar -tpar find. Mais mes autres points restent valables. Il existe un risque réel que votre commande telle qu'elle soit supprimée supprime un fichier non lié.
Gilles 'SO- arrête d'être méchant'
tar -tf tarbomb.tarimprimera les noms de fichiers un par ligne, vous pouvez donc faire tar -tf tarbomb.tar | while IFS=$'\n' read -r filename; do rm "$filename"; doneou similaire.
Mikel
0

Pas vraiment ce que vous avez demandé, mais comment utiliser un script "décompresser tout" au lieu de.

unzip *.zip

De cette façon, la sortie de chaque fichier va dans son propre répertoire.

#!/bin/bash
for f in *.zip ; do unzip -n "$f" -d "${f/%zip/out}"; done
Johan
la source
0

J'utilise la fonction suivante dans zsh:

ununzip () {
    rm -r $(unzip -l $1 | grep -v 'Archive:' | \
    grep '[/.]' | sed 's![^a-zA-Z]([a-zA-Z./])!\1!')
}

C'est-à-dire la substitution de commandes pour supprimer tous les fichiers dans la sortie nettoyée de unzip -l.

tar tvf pourrait être utilisé d'une manière similaire.

Edd Steel
la source