Annuler le désordre d'extraction de fichier tar

34

Je viens de décompresser une archive qui a produit un désordre de fichiers dans mon répertoire bien rangé. Par exemple:

user@comp:~/tidy$ tar xvf myarchive.tar
file1
file2
dir1/
dir1/file1
dir1/subdir1/
dir1/subdir1/file1
dir2/
dir2/file1
...

Je m'attendais à ce que le fichier tar ait été organisé dans un seul dossier (c'est-à-dire myarchive/), mais ce n'était pas le cas! Maintenant, j'ai quelque 190 fichiers et répertoires qui ont fait un abattage numérique dans ce qui était un répertoire organisé. Ces fichiers non tarés doivent être nettoyés.

Existe-t-il un moyen de «défaire» cela et de supprimer les fichiers et répertoires extraits de cette archive?


Merci pour les excellentes réponses ci-dessous. En résumé , voici ce qui fonctionne avec deux étapes (1) supprimer des fichiers et (2) supprimer une structure de répertoire vide dans l'ordre de conditionnement inverse (pour supprimer d'abord les répertoires externes):

tar tf myarchive.tar | xargs -d'\n' rm
tar tf myarchive.tar | tac | xargs -d'\n' rmdir

Et encore plus sûr, pour prévisualiser une exécution à sec des commandes en ajoutant echoaprès xargs.

Mike T
la source
Je suppose que vous pouvez répertorier les fichiers dans l'archive et les supprimer du répertoire actuel, mais cela semble potentiellement destructeur de données (données que vous souhaitez conserver). Je ne sais pas non plus comment écrire un script bash, donc je ne peux pas y aider.
Bob
Heureusement, rien n'a été écrasé!
Mike T
Je ne suis pas après le représentant et j'ai peur de paraître grincheux peu importe comment je mets ça, ce que je ne suis pas (j'ai bien aimé la réponse de slhck aussi et j'ai +1: ed it, et honnêtement: ± 15 rep est pas mon monde), mais vous finissez par utiliser ma réponse suggérée avec des tuyaux et xargs( tacau lieu de sort -rsimplement des cosmétiques), mais vous acceptez la réponse avec une substitution de processus qui, comme vous l'avez expliqué dans les commentaires, ne vous convenait pas? Veuillez également indiquer le xargs -d'\n'commutateur dans votre message si vous souhaitez résumer pour les futurs utilisateurs, afin qu'ils ne soient pas mordus par des espaces dans les noms de fichiers.
Daniel Andersson
@DanielAndersson, je n'ai jamais compris la nécessité de -d'\n'jusqu'à présent, et après une analyse plus approfondie, votre réponse est en fait plus proche de ce que j'ai utilisé.
Mike T
Tout à fait bien avec ça aussi, j'ai aimé la solution de @ Daniel :) La nécessité de -d'\n'réside dans le fait que si vous ne dites pas xargsde diviser les arguments sur de nouvelles lignes (ce que vous nourrissez) mais sur des espaces, alors un fichier avec le le nom folder1/some filesera lu comme folder1/someet name.
slhck

Réponses:

36
tar tf archive.tar

listera le contenu ligne par ligne.

Cela peut être xargsdirectement canalisé , mais attention : faites la suppression très soigneusement. Vous ne voulez pas simplement rm -rtout ce qui tar tfvous dit, car il peut inclure des répertoires qui n'étaient pas vides avant le déballage!

Vous pourriez faire

tar tf archive.tar | xargs -d'\n' rm -v
tar tf archive.tar | sort -r | xargs -d'\n' rmdir -v

pour supprimer d'abord tous les fichiers qui étaient dans l'archive, puis les répertoires laissés vides.

sort -r(glennjackman a suggéré tacau lieu de sort -rdans les commentaires de la réponse acceptée, qui fonctionne également car tarla sortie de est suffisamment régulière) est nécessaire pour supprimer les répertoires les plus profonds en premier; sinon, un cas où dir1contient un seul répertoire vide dir2quittera dir1après la rmdirpasse, car il n'était pas vide avant d' dir2être supprimé.

Cela va générer beaucoup de

rm: cannot remove `dir/': Is a directory

et

rmdir: failed to remove `dir/': Directory not empty
rmdir: failed to remove `file': Not a directory

Fermez-le 2>/dev/nullsi cela vous ennuie, mais je préférerais garder autant d'informations que possible sur le processus.

Et ne le faites pas tant que vous n'êtes pas sûr de trouver les bons fichiers. Et peut-être essayez rm -ide tout confirmer. Et avoir des sauvegardes, manger votre petit déjeuner, vous brosser les dents, etc.

Daniel Andersson
la source
Oui, il serait préférable de passer l' -d'\n'option à xargs.
Stéphane Gimenez
@slhck et Stéphane: Ah, oui, je vais mettre à jour. Je viens de faire un petit test, mais les fichiers n'avaient pas d'espace.
Daniel Andersson
1
Il faut noter que BSD xargsn'a pas -d, donc vous avez besoin de la variante GNU si vous êtes une pauvre âme comme moi.
slhck
10

Listez le contenu du fichier tar comme suit:

tar tzf myarchive.tar

Ensuite, supprimez ces noms de fichiers en itérant sur cette liste:

while IFS= read -r file; do echo "$file"; done < <(tar tzf myarchive.tar.gz)

Cela reste juste la liste des fichiers qui seraient supprimés. Remplacez echopar rmsi vous êtes vraiment sûr que ce sont ceux que vous souhaitez supprimer. Et peut-être faire une sauvegarde pour être sûr.

Dans un deuxième passage, supprimez les répertoires qui restent:

while IFS= read -r file; do rmdir "$file"; done < <(tar tzf myarchive.tar.gz)

Cela empêche la suppression des répertoires avec s'ils existaient déjà auparavant.


Une autre astuce intéressante de @glennjackman, qui préserve l'ordre des fichiers, en commençant par les plus profonds. Encore une fois, retirez echolorsque vous avez terminé.

tar tvf myarchive.tar | tac | xargs -d'\n' echo rm

Cela pourrait ensuite être suivi par le rmdirnettoyage normal .

slhck
la source
Étrange façon d'écrire une pipe.
Stéphane Gimenez
Ce n'est pas une pipe. C'est une substitution de processus et je préfère cela à une simple tuyauterie lorsqu'il est utilisé en combinaison avec whilepour boucler sur un ensemble d'enregistrements. Je viens de m'y habituer. @ sté
slhck
1
Désolé pour le peu de retard, j'ai remarqué que l'utilisation rm -rfpouvait supprimer des fichiers qui n'étaient pas de l'archive mais à l'intérieur d'un répertoire portant le même nom que celui de l'archive. Mieux vaut être prudent ici et utiliser rmdirdans un deuxième passage.
Stéphane Gimenez
1
En fait, la deuxième passe rmdirdoit être exécutée pour chaque niveau d'imbrication des répertoires. Donc, il sera nettoyé subdir1lors de la première passe, mais quitte dir1car il a essayé de supprimer ce premier alors qu'il n'était pas vide à l'époque. Cette commande peut être exécutée une fois si la liste des fichiers peut être triée en sens inverse.
Mike T
3
Si vous souhaitez supprimer le dans l'ordre inverse: tar tvf arch.tar | tac | xargs echo rm(supprimez l'écho lorsque vous êtes sûr)
glenn jackman
2

Voici une possibilité qui prendra les fichiers extraits et les déplacera dans un sous-répertoire, nettoyant votre dossier principal.

    #!/usr/bin/perl -w

    use strict;
    use Getopt::Long;

    my $clean_folder = "clean";
    my $DRY_RUN;
    die "Usage: $0 [--dry] [--clean=dir-name]\n"
        if ( !GetOptions("dry!" => \$DRY_RUN,
                         "clean=s" => \$clean_folder));

    # Protect the 'clean_folder' string from shell substitution
    $clean_folder =~ s/'/'\\''/g;

    # Process the "tar tv" listing and output a shell script.
    print "#!/bin/sh\n" if ( !$DRY_RUN );
    while (<>)
    {
        chomp;

        # Strip out permissions string and the directory entry from the 'tar' list
        my $perms = substr($_, 0, 10);
        my $dirent = substr($_, 48);

        # Drop entries that are in subdirectories
        next if ( $dirent =~ m:/.: );

        # If we're in "dry run" mode, just list the permissions and the directory
        # entries.
        #
        if ( $DRY_RUN )
        {
            print "$perms|$dirent\n";
            next;
        }

        # Emit the shell code to clean up the folder
        $dirent =~ s/'/'\\''/g;
        print "mv -i '$dirent' '$clean_folder'/.\n";
    }

Enregistrez-le dans le fichier fix-tar.pl, puis exécutez-le comme ceci:

$ tar tvf myarchive.tar | perl fix-tar.pl --dry

Cela confirmera que votre tarliste est comme la mienne. Vous devriez obtenir une sortie comme:

-rw-rw-r--|batch
-rw-rw-r--|book-report.png
-rwx------|CaseReports.png
-rw-rw-r--|caseTree.png
-rw-rw-r--|tree.png
drwxrwxr-x|sample/

Si cela semble bon, exécutez-le à nouveau comme ceci:

$ mkdir cleanup
$ tar tvf myarchive.tar | perl fix-tar.pl --clean=cleanup > fixup.sh

Le fixup.shscript sera les commandes shell qui déplaceront les fichiers et répertoires de niveau supérieur dans un dossier "propre" (dans ce cas, le dossier appelé cleanup). Jetez un œil à travers ce script pour confirmer que tout est casher. Si c'est le cas, vous pouvez maintenant nettoyer votre gâchis avec:

$ sh fixup.sh

Je préfère ce type de nettoyage car il ne détruit rien qui ne soit déjà détruit en étant écrasé par cette initiale tar xv.

Remarque: si cette sortie initiale de fonctionnement à sec ne semble pas correcte, vous devriez pouvoir jouer avec les chiffres des deux substrappels de fonction jusqu'à ce qu'ils semblent corrects. La $permsvariable n'est utilisée que pour la marche à sec, donc seule la $direntsous - chaîne doit être correcte.

Une autre chose: vous devrez peut-être utiliser l' taroption --numeric-ownersi les noms d'utilisateur et / ou les noms de groupe dans la tarliste font que les noms commencent dans une colonne imprévisible.

S2VpdGgA
la source
1

Ce type d'archives (antisociales) s'appelle une bombe tar à cause de ce qu'elle fait. Une fois que l'une de ces "explosions" sur vous, les solutions dans les autres réponses sont bien meilleures que ce que j'aurais suggéré.

Cependant, la meilleure "solution" consiste à éviter le problème en premier lieu.

La façon la plus simple (la plus paresseuse) de le faire est de toujours décompresser une archive tar dans un répertoire vide. S'il comprend un répertoire de niveau supérieur, il vous suffit de le déplacer vers la destination souhaitée. Sinon, renommez simplement votre répertoire de travail (celui qui était vide) et déplacez-le à l'emplacement souhaité.

Si vous voulez juste faire les choses correctement la première fois, vous pouvez exécuter tar -tvf archive-file.tar | moins et il listera le contenu de l'archive afin que vous puissiez voir comment il est structuré et ensuite faire ce qui est nécessaire pour l'extraire à l'emplacement souhaité pour commencer.

L'option t est également utile si vous souhaitez inspecter le contenu d'une archive juste pour voir si elle contient quelque chose que vous recherchez. Si tel est le cas, vous pouvez éventuellement extraire le ou les fichiers souhaités.

Joe
la source