Annulla il disordine di estrazione del file tar


34

Ho appena decompresso un archivio che ha prodotto un disordine di file nella mia directory ordinata. Per esempio:

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

Mi aspettavo che il file tar sarebbe stato organizzato in una singola cartella (cioè, myarchive/), ma non lo era! Ora ho circa 190 file e directory che sono stati archiviati digitalmente in quella che era una directory organizzata. Questi file non ancora caricati devono essere ripuliti.

C'è un modo per "annullare" questo ed eliminare i file e le directory che sono stati estratti da questo archivio?


Grazie per le eccellenti risposte di seguito. In sintesi , ecco cosa funziona con due passaggi (1) elimina i file e (2) elimina la struttura di directory vuota in ordine inverso di imballaggio (per eliminare prima le directory esterne):

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

E ancora più sicuro, visualizzare in anteprima una serie di comandi a secco aggiungendo echodopo xargs.


Suppongo che potresti elencare i file nell'archivio ed eliminarli dalla directory corrente, ma ciò sembra potenzialmente distruttivo per i dati (dati che vuoi conservare). Inoltre non ho idea di come scrivere uno script bash, quindi non posso farci nulla.
Bob,

Fortunatamente, nulla è stato sovrascritto!
Mike T,

Non sto cercando il rappresentante e temo che suonerò irritabile, non importa come lo metto, che non lo sono (mi è piaciuta anche la risposta di Slhck e ho +1: edito, e onestamente: ± 15 rep è non il mio mondo), ma finisci per usare la mia risposta suggerita con le pipe e xargs( tacinvece che sort -rsolo con i cosmetici), ma accetti la risposta con la sostituzione del processo che, come spiegato nei commenti, non ti andava bene? Inoltre, si prega di dare il xargs -d'\n'passaggio nel tuo post se si desidera riepilogare per gli utenti futuri, in modo che non vengano morsi da spazi nei nomi dei file.
Daniel Andersson,

@DanielAndersson, non ho mai capito la necessità di -d'\n'fino ad ora, e dopo ulteriori analisi la tua risposta è in realtà più vicina a quella che ho usato.
Mike T,

Totalmente bene anche con quello, mi è piaciuta la soluzione di Daniel @ :) La necessità di -d'\n'risiede nel fatto che se non dici xargsdi dividere argomenti su nuove righe (che è ciò che stai alimentando) ma su spazi, quindi un file con il il nome folder1/some fileverrà letto come folder1/somee name.
Slhck,

Risposte:


36
tar tf archive.tar

elencherà i contenuti riga per riga.

Questo può essere convogliato xargsdirettamente, ma attenzione : fai la cancellazione con molta attenzione. Lei non vuole solo rm -rtutto ciò che tar tfsi dice, dal momento che potrebbe includere le directory che non erano vuote prima di disimballare!

Si potrebbe fare

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

per rimuovere prima tutti i file presenti nell'archivio, quindi le directory che rimangono vuote.

sort -r(glennjackman ha suggerito tacinvece di inserire sort -rnei commenti la risposta accettata, che funziona anche perché tarl'output è abbastanza regolare) è necessario per eliminare prima le directory più profonde; altrimenti un caso in cui dir1contiene una singola directory vuota dir2lascerà dir1dopo il rmdirpassaggio, poiché è stato non vuoto prima dir2è stato rimosso.

Questo genererà molto

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

e

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

2>/dev/nullStai zitto se ti dà fastidio, ma preferirei conservare quante più informazioni possibili sul processo.

E non farlo finché non sei sicuro di abbinare i file giusti. E forse prova rm -ia confermare tutto. E fai backup, fai colazione, lavati i denti, ecc.


Sì, sarebbe meglio passare l' -d'\n'opzione a xargs.
Stéphane Gimenez,

@slhck e Stéphane: Ah, sì, aggiornerò. Ho appena fatto un piccolo test case, ma i file non avevano spazi.
Daniel Andersson,

1
Va notato che BSD xargsnon ha -d, quindi hai bisogno della variante GNU se sei un'anima povera come me.
slhck,

10

Elencare i contenuti del file tar in questo modo:

tar tzf myarchive.tar

Quindi, elimina quei nomi di file ripetendo quell'elenco:

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

Questo continuerà a elencare i file che verrebbero eliminati. Sostituisci echocon rmse sei davvero sicuro che questi sono quelli che vuoi rimuovere. E forse fare un backup per essere sicuri.

In un secondo passaggio, rimuovere le directory rimaste:

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

Ciò impedisce che le directory con vengano eliminate se esistevano già in precedenza.


Un altro bel trucco di @glennjackman, che conserva l'ordine dei file, a partire da quelli più profondi. Ancora una volta, rimuovi echoal termine.

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

Questo potrebbe quindi essere seguito dalla normale rmdirpulizia.


Strano modo di scrivere una pipa.
Stéphane Gimenez,

E ' non è una pipa. È una sostituzione del processo e preferisco questo rispetto alle semplici tubazioni quando usato in combinazione con un whileciclo su un set di record. Ci siamo appena abituati. @ sté
slhck,

1
Scusate il piccolo ritardo, ho notato che l'uso rm -rfpotrebbe eliminare i file che non provenivano dall'archivio ma all'interno di una directory che ha lo stesso nome di uno dall'archivio. Meglio stare attenti qui e usarli rmdirin un secondo passaggio.
Stéphane Gimenez,

1
In realtà il secondo passaggio con rmdirdeve essere eseguito per ogni livello di annidamento delle directory. Quindi ripulirà subdir1al primo passaggio, ma se ne andrà dir1poiché ha tentato di eliminarlo prima quando non era vuoto al momento. Questo comando può essere eseguito una volta se l'elenco dei file può essere invertito.
Mike T,

3
Se si desidera eliminare il nell'ordine inverso: tar tvf arch.tar | tac | xargs echo rm(rimuovere l'eco quando si è sicuri)
Glenn Jackman,

2

Ecco una possibilità che prenderà i file estratti e li sposterà in una sottodirectory, ripulendo la cartella principale.

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

Salvalo nel file fix-tar.ple quindi eseguilo in questo modo:

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

Ciò confermerà che la tua tarlista è come la mia. Dovresti ottenere un output come:

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

Se sembra buono, quindi eseguirlo di nuovo in questo modo:

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

Lo fixup.shscript saranno i comandi della shell che sposteranno i file e le directory di livello superiore in una cartella "pulita" (in questo caso, la cartella chiamata cleanup). Dai un'occhiata a questo script per confermare che è tutto kosher. Se lo è, ora puoi ripulire il tuo pasticcio con:

$ sh fixup.sh

Preferisco questo tipo di pulizia perché non distrugge nulla che non sia già distrutto dall'essere sovrascritto da quell'iniziale tar xv.

Nota: se l'output iniziale di esecuzione a secco non sembra corretto, si dovrebbe essere in grado di giocherellare con i numeri nelle due substrchiamate di funzione fino a quando non appaiono corretti. La $permsvariabile viene utilizzata solo per la corsa a secco, quindi in realtà solo la $direntsottostringa deve essere corretta.

Un'altra cosa: potrebbe essere necessario utilizzare l' taropzione --numeric-ownerse i nomi utente e / o i nomi di gruppo tarnell'elenco fanno sì che i nomi inizino in una colonna imprevedibile.


1

Quel tipo di archivio (antisociale) è chiamato una bomba di catrame a causa di ciò che fa. Una volta che una di queste "esplode" su di te, le soluzioni nelle altre risposte sono molto migliori di quanto avrei suggerito.

La migliore "soluzione", tuttavia, è quella di prevenire il problema in primo luogo.

Il modo più semplice (più pigro) per farlo è decomprimere sempre un archivio tar in una directory vuota. Se include una directory di livello superiore, è sufficiente spostarla nella destinazione desiderata. In caso contrario, basta rinominare la directory di lavoro (quella vuota) e spostarla nella posizione desiderata.

Se vuoi solo farlo bene la prima volta, puoi eseguire tar -tvf archive-file.tar | meno ed elencherà il contenuto dell'archivio in modo da poter vedere come è strutturato e quindi fare ciò che è necessario per estrarlo nella posizione desiderata per iniziare.

L'opzione t è utile anche se si desidera ispezionare il contenuto di un archivio solo per vedere se contiene qualcosa che si sta cercando. In tal caso, puoi, facoltativamente, estrarre solo i file desiderati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.