Rückgängigmachen der Unordnung beim Extrahieren von Tar-Dateien

34

Ich habe gerade ein Archiv entpackt, das ein Durcheinander von Dateien in meinem aufgeräumten Verzeichnis erzeugt hat. Beispielsweise:

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

Ich hatte erwartet, dass die TAR-Datei in einem einzigen Ordner (dh myarchive/) organisiert wäre, aber es war nicht! Jetzt habe ich ungefähr 190 Dateien und Verzeichnisse, die digital in ein organisiertes Verzeichnis verschoben wurden. Diese Dateien müssen bereinigt werden.

Gibt es eine Möglichkeit, dies rückgängig zu machen und die Dateien und Verzeichnisse zu löschen, die aus diesem Archiv extrahiert wurden?


Vielen Dank für die hervorragenden Antworten unten. Zusammenfassend funktioniert Folgendes mit zwei Schritten: (1) Löschen von Dateien und (2) Löschen der leeren Verzeichnisstruktur in umgekehrter Reihenfolge (Löschen der äußeren Verzeichnisse zuerst):

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

Noch sicherer ist es, eine Vorschau der Befehle anzuzeigen, indem Sie sie echonachher anhängen xargs.

Mike T
quelle
Sie könnten die Dateien im Archiv auflisten und sie aus dem aktuellen Verzeichnis löschen, aber das fühlt sich potenziell datenschädlich an (Daten, die Sie behalten möchten). Ich habe auch keine Ahnung, wie man ein Bash-Skript schreibt, deshalb kann ich dort nicht helfen.
Bob
Zum Glück wurde nichts überschrieben!
Mike T
Ich bin nicht hinter der Wiederholung her und ich fürchte, ich werde launisch klingen, egal wie ich das formuliere, was ich nicht bin nicht meine Welt), aber am Ende verwenden Sie meine vorgeschlagene Antwort mit Pfeifen und xargs( tacstatt sort -rnur Kosmetik), aber Sie akzeptieren die Antwort mit Prozessersetzung, die, wie Sie in den Kommentaren erklärt haben, nicht zu Ihnen passte? Geben Sie außerdem xargs -d'\n'in Ihrem Beitrag den Schalter an, wenn Sie eine Zusammenfassung für zukünftige Benutzer erstellen möchten, damit diese nicht von Leerzeichen in Dateinamen gebissen werden.
Daniel Andersson
@DanielAndersson, ich habe die Notwendigkeit von -d'\n'bis jetzt nie verstanden , und nach weiterer Analyse ist Ihre Antwort tatsächlich näher an dem, was ich verwendet habe.
Mike T
Völlig in Ordnung auch damit, mochte @ Daniels Lösung :) Die Notwendigkeit -d'\n'liegt in der Tatsache, dass, wenn Sie nicht sagen xargs, Argumente in neue Zeilen aufzuteilen (was Sie einspeisen), sondern in Leerzeichen, dann eine Datei mit dem Name folder1/some filewird als folder1/someund gelesen name.
Slhck

Antworten:

36
tar tf archive.tar

listet den Inhalt zeilenweise auf.

Dies kann xargsdirekt weitergeleitet werden, aber Vorsicht : Führen Sie den Löschvorgang sehr sorgfältig durch. Sie wollen nicht nur rm -ralles, was tar tfIhnen sagt, da es möglicherweise Verzeichnisse enthält, die vor dem Entpacken nicht leer waren!

Du könntest es tun

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

Entfernen Sie zuerst alle Dateien, die sich im Archiv befanden, und anschließend die leeren Verzeichnisse.

sort -r(glennjackman schlug vor, tacanstatt sort -rin den Kommentaren auf die akzeptierte Antwort zu antworten, was auch funktioniert, da tardie Ausgabe regelmäßig genug ist) wird benötigt, um die tiefsten Verzeichnisse zuerst zu löschen; Andernfalls wird ein Fall, in dem dir1ein einzelnes leeres Verzeichnis enthalten dir2ist, dir1nach dem rmdirDurchlauf verlassen, da es zuvor nicht leer dir2war und entfernt wurde.

Dies wird viel erzeugen

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

und

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

Halt die 2>/dev/nullKlappe, wenn es dich nervt, aber ich würde es vorziehen, so viele Informationen wie möglich über den Prozess zu behalten.

Und tun Sie das erst, wenn Sie sicher sind, dass Sie die richtigen Dateien gefunden haben. Und versuchen Sie vielleicht rm -i, alles zu bestätigen. Und sichern Sie sich, frühstücken Sie, putzen Sie sich die Zähne usw.

Daniel Andersson
quelle
Ja, es wäre besser, die -d'\n'Option zu übergeben xargs.
Stéphane Gimenez
@slhck und Stéphane: Ah ja, ich werde updaten. Ich habe gerade einen kleinen Testfall gemacht, aber die Dateien hatten keine Leerzeichen.
Daniel Andersson
1
Sollte angemerkt werden, dass BSD xargskeine hat -d, so dass Sie die GNU-Variante benötigen, wenn Sie eine arme Seele wie ich sind.
Slhck
10

Listen Sie den Inhalt der tar-Datei folgendermaßen auf:

tar tzf myarchive.tar

Löschen Sie dann diese Dateinamen, indem Sie diese Liste durchlaufen:

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

Dies listet immer noch nur die Dateien auf, die gelöscht werden würden. Ersetzen Sie echodurch, rmwenn Sie wirklich sicher sind, dass Sie diese entfernen möchten. Und vielleicht machen Sie ein Backup, um sicherzugehen.

Entfernen Sie in einem zweiten Durchgang die verbleibenden Verzeichnisse:

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

Auf diese Weise wird verhindert, dass Verzeichnisse mit gelöscht werden, wenn sie zuvor bereits vorhanden waren.


Ein weiterer netter Trick von @glennjackman, bei dem die Reihenfolge der Dateien beibehalten wird, beginnend mit den tiefsten. Wieder entfernen, echowenn Sie fertig sind.

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

Darauf könnte dann die normale rmdirBereinigung folgen .

slhck
quelle
Seltsame Art, eine Pfeife zu schreiben.
Stéphane Gimenez
Es ist keine Pfeife. Es ist die Prozessersetzung und ich bevorzuge dies gegenüber dem einfachen Piping, wenn es in Kombination mit whileeiner Schleife über eine Reihe von Datensätzen verwendet wird. Ich habe mich gerade daran gewöhnt. @ sté
slhck
1
Entschuldigung für die kleine Verzögerung, ich habe festgestellt, dass mit rm -rfDateien gelöscht werden können, die nicht aus dem Archiv stammen, sondern sich in einem Verzeichnis befinden, das denselben Namen hat wie eines aus dem Archiv. Sei hier besser vorsichtig und benutze es rmdirin einem zweiten Durchgang.
Stéphane Gimenez
1
Tatsächlich muss der zweite Durchgang mit rmdirfür jede Ebene der Verschachtelung von Verzeichnissen ausgeführt werden. So wird es subdir1beim ersten Durchlauf bereinigt , aber verlassen, dir1da es versucht hat, dies zuerst zu löschen, als es zu der Zeit noch nicht leer war. Dieser Befehl kann einmal ausgeführt werden, wenn die Dateiliste rücksortiert werden kann.
Mike T
3
Wenn Sie das in umgekehrter Reihenfolge löschen möchten: tar tvf arch.tar | tac | xargs echo rm(Entfernen Sie das Echo, wenn Sie sicher sind)
Glenn Jackman
2

Hier ist eine Möglichkeit, die extrahierten Dateien in ein Unterverzeichnis zu verschieben und den Hauptordner zu bereinigen.

    #!/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";
    }

Speichern Sie dies in der Datei fix-tar.plund führen Sie es dann wie folgt aus:

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

Dadurch wird bestätigt, dass Ihre tarListe meiner entspricht. Sie sollten eine Ausgabe wie folgt erhalten:

-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/

Wenn das gut aussieht, dann starte es nochmal so:

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

Das fixup.shSkript besteht aus den Shell-Befehlen, mit denen die Dateien und Verzeichnisse der obersten Ebene in einen "sauberen" Ordner verschoben werden (in diesem Fall in den aufgerufenen Ordner cleanup). Werfen Sie einen Blick in dieses Skript, um zu bestätigen, dass alles koscher ist. Wenn dies der Fall ist, können Sie jetzt Ihr Chaos aufräumen mit:

$ sh fixup.sh

Ich bevorzuge diese Art der Bereinigung, weil sie nichts zerstört, was noch nicht durch das Überschreiben mit dieser Initiale zerstört wurde tar xv.

Hinweis: Wenn die anfängliche Trockenlaufausgabe nicht richtig aussieht, sollten Sie in der Lage sein, mit den Zahlen in den beiden substrFunktionsaufrufen zu fummeln, bis sie richtig aussehen. Die $permsVariable wird nur für den Probelauf verwendet, sodass wirklich nur der $direntTeilstring korrekt sein muss.

Eine andere Sache: Möglicherweise müssen Sie diese tarOption verwenden, --numeric-ownerwenn die Benutzernamen und / oder Gruppennamen in der tarListe dazu führen, dass die Namen in einer unvorhersehbaren Spalte beginnen.

S2VpdGgA
quelle
1

Diese Art von (asozialem) Archiv wird aufgrund ihrer Funktion als Teerbombe bezeichnet. Sobald eine dieser "Explosionen" bei Ihnen auftritt, sind die Lösungen in den anderen Antworten weitaus besser als von mir vorgeschlagen.

Die beste "Lösung" besteht jedoch darin, das Problem zunächst zu vermeiden.

Der einfachste (faulste) Weg, dies zu tun, besteht darin, ein tar-Archiv immer in ein leeres Verzeichnis zu entpacken. Wenn es ein Verzeichnis der obersten Ebene enthält, verschieben Sie es einfach an das gewünschte Ziel. Wenn nicht, benennen Sie einfach Ihr Arbeitsverzeichnis (das leere) um und verschieben Sie es an den gewünschten Ort.

Wenn Sie es nur beim ersten Mal richtig machen möchten, können Sie tar -tvf archive-file.tar | ausführen In diesem Fall wird der Inhalt des Archivs aufgelistet, sodass Sie sehen können, wie es strukturiert ist, und anschließend die erforderlichen Schritte ausführen, um es an den gewünschten Speicherort zu extrahieren.

Die Option t ist auch nützlich, wenn Sie den Inhalt eines Archivs überprüfen möchten, um festzustellen, ob sich darin etwas befindet, nach dem Sie suchen. In diesem Fall können Sie optional nur die gewünschten Dateien extrahieren.

Joe
quelle