Cofnij usuwanie pliku tar

34

Właśnie rozpakowałem archiwum, które produkowało bałagan plików w moim uporządkowanym katalogu. Na przykład:

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

Spodziewałem się, że plik tar zostałby zorganizowany w jednym folderze (tj. myarchive/), Ale tak nie było! Teraz mam około 190 plików i katalogów, które zostały cyfrowo zakodowane w tym, co było zorganizowanym katalogiem. Te nieopracowane pliki muszą zostać wyczyszczone.

Czy jest jakiś sposób, aby to „cofnąć” i usunąć pliki i katalogi wyodrębnione z tego archiwum?


Dzięki za doskonałe odpowiedzi poniżej. Podsumowując , oto, co działa w dwóch krokach: (1) usunięcie plików i (2) usunięcie pustej struktury katalogów w odwrotnej kolejności pakowania (aby najpierw usunąć katalog zewnętrzny):

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

Jeszcze bezpieczniej, aby wyświetlić podgląd suchego polecenia, dodając echopo nim xargs.

Mike T.
źródło
Wydaje mi się, że możesz wymienić pliki w archiwum i usunąć je z bieżącego katalogu, ale wydaje się to potencjalnie destrukcyjne (dane, które chcesz zachować). Nie mam też pojęcia, jak napisać skrypt bash, więc nie mogę nic na to poradzić.
Bob
Na szczęście nic nie zostało nadpisane!
Mike T
Nie jestem po powtórzeniu i obawiam się, że zabrzmią zepsute, bez względu na to, jak to ułożę, co nie jest (podobało mi się również slhck i dałem +1: ed, i szczerze: ± 15 powtórzeń nie mój świat), ale w końcu używasz mojej sugerowanej odpowiedzi z fajkami i xargs( taczamiast sort -rto tylko kosmetyki), ale akceptujesz odpowiedź z zastąpieniem procesu, który, jak wyjaśniłeś w komentarzach, nie pasował? xargs -d'\n'Jeśli chcesz podsumować dla przyszłych użytkowników, podaj przełącznik w swoim poście, aby nie zostali ukąszeni spacjami w nazwach plików.
Daniel Andersson
@DanielAndersson, -d'\n'do tej pory nigdy nie rozumiałem konieczności , a po dalszej analizie twoja odpowiedź jest bliższa temu, czego użyłem.
Mike T
To też w porządku, podobało mi się rozwiązanie @ Daniela :) Konieczność -d'\n'polega na tym, że jeśli nie mówisz xargso dzieleniu argumentów na nowe wiersze (które karmisz), ale na spacje, plik z nazwa folder1/some filezostanie odczytana jako folder1/somei name.
slhck

Odpowiedzi:

36
tar tf archive.tar

wyświetli zawartość linia po linii.

Można to przesłać xargsbezpośrednio, ale uwaga : usuń bardzo ostrożnie. Ty nie chcesz po prostu rm -rwszystko, co tar tfmówi pan, ponieważ może ona zawierać katalogi, które nie były puste przed rozpakowaniem!

Mógłbyś

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

aby najpierw usunąć wszystkie pliki, które były w archiwum, a następnie puste katalogi.

sort -r(glennjackman zasugerował taczamiast sort -rw komentarzach do zaakceptowanej odpowiedzi, co również działa, ponieważ tardane wyjściowe są wystarczająco regularne) jest konieczne, aby najpierw usunąć najgłębsze katalogi; inaczej przypadek, w którym dir1zawiera pojedynczy pusty katalog dir2pozostawi dir1po rmdirpodaniu, ponieważ było nie opróżniać zanim dir2został usunięty.

To wygeneruje dużo

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

i

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

Zamknij to, 2>/dev/nulljeśli cię to denerwuje, ale wolałbym zachować jak najwięcej informacji o procesie.

I nie rób tego, dopóki nie upewnisz się, że pasujesz do właściwych plików. I może spróbuj rm -iwszystko potwierdzić. I rób kopie zapasowe, jedz śniadanie, myj zęby itp.

Daniel Andersson
źródło
Tak, lepiej byłoby przekazać -d'\n'opcję xargs.
Stéphane Gimenez
@slhck i Stéphane: Ach, tak, zaktualizuję. Zrobiłem tylko mały przypadek testowy, ale pliki nie miały spacji.
Daniel Andersson
1
Należy zauważyć, że BSD xargsnie ma -d, więc potrzebujesz wersji GNU, jeśli jesteś biedną duszą, taką jak ja.
slhck
10

Wyświetl zawartość pliku tar w następujący sposób:

tar tzf myarchive.tar

Następnie usuń te nazwy plików, iterując po tej liście:

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

Nadal będzie tylko lista plików, które zostaną usunięte. Wymień echosię rm, jeśli jesteś pewien, to są te, które chcesz usunąć. A może dla pewności wykonaj kopię zapasową.

W drugim przejściu usuń pozostałe katalogi:

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

Zapobiega to usuwaniu katalogów z, jeśli już istniały wcześniej.


Kolejna fajna sztuczka autorstwa @glennjackman, która zachowuje porządek plików, poczynając od najgłębszych. Ponownie usuń echopo zakończeniu.

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

Następnie może nastąpić normalne rmdirczyszczenie.

slhck
źródło
Dziwny sposób na napisanie fajki.
Stéphane Gimenez
To nie jest fajka. Jest to podstawianie procesów i wolę to niż proste orurowanie, gdy jest używane w połączeniu z whilepętlą nad zestawem rekordów. Właśnie się do tego przyzwyczaiłem. @ sté
slhck
1
Przepraszam za małe opóźnienie, zauważyłem, że użycie rm -rfmoże usunąć pliki, które nie były z archiwum, ale w katalogu o tej samej nazwie co jeden z archiwum. Lepiej uważaj tutaj i użyj rmdirdrugiego przejścia.
Stéphane Gimenez
1
Właściwie należy uruchomić drugie przejście z rmdirkażdym poziomem zagnieżdżenia katalogów. Więc wyczyści się subdir1przy pierwszym przejściu, ale odejdź, dir1ponieważ próbował usunąć to pierwszy, gdy nie był pusty. To polecenie można wykonać raz, jeśli listę plików można posortować odwrotnie.
Mike T
3
Jeśli chcesz usunąć w odwrotnej kolejności: tar tvf arch.tar | tac | xargs echo rm(usuń echo, gdy będziesz pewien)
glenn jackman
2

Oto możliwość, która zabierze wyodrębnione pliki i przeniesie je do podkatalogu, czyszcząc główny folder.

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

Zapisz to w pliku, fix-tar.pla następnie wykonaj w następujący sposób:

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

To potwierdzi, że twoja tarlista jest jak moja. Powinieneś otrzymać dane wyjściowe takie jak:

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

Jeśli to wygląda dobrze, uruchom ponownie w następujący sposób:

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

fixup.shSkrypt będzie skorupy polecenia, które będzie przenieść pliki na najwyższym poziomie i katalogów w folderze „czystej” (w tym przypadku, folder o nazwie cleanup). Przejrzyj ten skrypt, aby potwierdzić, że wszystko jest koszerne. Jeśli tak, możesz teraz posprzątać swój bałagan za pomocą:

$ sh fixup.sh

Wolę ten rodzaj czyszczenia, ponieważ nie niszczy niczego, co nie zostało już zniszczone przez zastąpienie tą inicjałem tar xv.

Uwaga: jeśli to początkowe wyjście suchobiegu nie wygląda dobrze, powinieneś być w stanie manipulować liczbami w dwóch substrwywołaniach funkcji, dopóki nie będą wyglądać poprawnie. $permsZmienna jest używana tylko dla sucho więc tak naprawdę tylko $direntpotrzeby podciąg być właściwa.

Jeszcze jedno: może być konieczne użycie tej taropcji, --numeric-ownerjeśli nazwy użytkowników i / lub nazwy grup na tarliście powodują, że nazwy zaczynają się w nieprzewidywalnej kolumnie.

S2VpdGgA
źródło
1

Tego rodzaju (antyspołeczne) archiwum nazywa się bombą tarową ze względu na to, co robi. Gdy jedno z nich „eksploduje” na tobie, rozwiązania w innych odpowiedziach są znacznie lepsze niż to, co sugerowałbym.

Najlepszym „rozwiązaniem” jest jednak przede wszystkim zapobieganie problemowi.

Najłatwiejszym (leniwym) sposobem na zrobienie tego jest zawsze rozpakowanie archiwum tar do pustego katalogu. Jeśli zawiera katalog najwyższego poziomu, wystarczy przenieść go do żądanego miejsca docelowego. Jeśli nie, po prostu zmień nazwę katalogu roboczego (ten, który był pusty) i przenieś go do żądanej lokalizacji.

Jeśli chcesz to zrobić za pierwszym razem, możesz uruchomić tar -tvf archive-file.tar | mniej, a wyświetli zawartość archiwum, dzięki czemu można zobaczyć, jak jest on skonstruowany, a następnie zrobić wszystko, co konieczne, aby wyodrębnić go do wybranej lokalizacji na początek.

Opcja t przydaje się również, jeśli chcesz sprawdzić zawartość archiwum, aby sprawdzić, czy zawiera ono coś, czego szukasz. Jeśli tak, możesz opcjonalnie po prostu wyodrębnić żądane pliki.

Joe
źródło