Deshacer lío de extracción de archivos tar

34

Acabo de descomprimir un archivo que produjo un desastre de archivos en mi ordenado directorio. Por ejemplo:

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

Esperaba que el archivo tar se hubiera organizado en una sola carpeta (es decir, myarchive/ ), ¡pero no fue así! Ahora tengo unos 190 archivos y directorios que han vomitado digitalmente en lo que era un directorio organizado. Estos archivos sin archivo necesitan ser limpiados.

¿Hay alguna forma de "deshacer" esto y eliminar los archivos y directorios que se extrajeron de este archivo?


Gracias por las excelentes respuestas a continuación. En resumen , esto es lo que funciona con dos pasos (1) eliminar archivos y (2) eliminar la estructura de directorios vacía en orden inverso al empaque (para eliminar primero los directorios externos):

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

Y aún más seguro, para obtener una vista previa de una ejecución en seco de los comandos agregando echodespués xargs.

Mike T
fuente
Supongo que podría enumerar los archivos en el archivo y eliminarlos del directorio actual, pero eso se siente potencialmente destructivo de datos (datos que desea mantener). Tampoco tengo idea de cómo escribir un script bash, por lo que no puedo evitarlo.
Bob
Afortunadamente, no se sobrescribió nada!
Mike T
No busco el representante y me temo que pareceré malhumorado sin importar cómo lo ponga, lo cual no es así (también me gustó la respuesta de slhck y lo hice +1: y honestamente: ± 15 rep es no es mi mundo), pero terminas usando mi respuesta sugerida con tubos y xargs(en taclugar de sort -rsolo cosméticos), pero aceptas la respuesta con la sustitución del proceso que, como explicaste en los comentarios, ¿no te quedaba bien? Además, active el xargs -d'\n'cambio en su publicación si desea hacer un resumen para futuros usuarios, para que no se muerdan con espacios en los nombres de archivo.
Daniel Andersson
@DanielAndersson, nunca entendí la necesidad de hacerlo -d'\n'hasta ahora, y después de un análisis más profundo, su respuesta está realmente más cerca de lo que usé.
Mike T
Totalmente bien con eso también, me gustó la solución de @Daniel :) La necesidad de -d'\n'radica en el hecho de que si no le dice xargsque divida los argumentos en nuevas líneas (que es lo que está alimentando) pero en espacios, entonces un archivo con el el nombre folder1/some filese leerá como folder1/somey name.
slhck

Respuestas:

36
tar tf archive.tar

enumerará los contenidos línea por línea.

Esto se puede canalizar xargsdirectamente, pero tenga cuidado : elimine con mucho cuidado. ¡ No desea simplemente rm -rtodo lo que tar tfle dice, ya que puede incluir directorios que no estaban vacíos antes de desempacar!

Podrías hacerlo

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

para eliminar primero todos los archivos que estaban en el archivo y luego los directorios que quedan vacíos.

sort -r(se sugiere glennjackman en taclugar de sort -ren los comentarios a la respuesta aceptada, que también funciona ya que tarel resultado es lo suficientemente regular) es necesario eliminar primero los directorios más profundos; de lo contrario, un caso donde dir1contiene un único directorio vacío dir2se dejará dir1después del rmdirpase, ya que no estaba vacío antes de que dir2se eliminara.

Esto generará una gran cantidad de

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

y

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

Cállate con esto 2>/dev/nullsi te molesta, pero preferiría mantener tanta información sobre el proceso como sea posible.

Y no lo haga hasta que esté seguro de que coincide con los archivos correctos. Y tal vez intente rm -iconfirmar todo. Y tener refuerzos, desayunar, cepillarse los dientes, etc.

Daniel Andersson
fuente
Sí, sería mejor pasar la -d'\n'opción a xargs.
Stéphane Gimenez
@slhck y Stéphane: Ah, sí, actualizaré. Acabo de hacer un pequeño caso de prueba, pero los archivos no tenían espacios.
Daniel Andersson
1
Cabe señalar que BSD xargsno tiene -d, por lo que necesita la variante GNU si es un alma pobre como yo.
slhck
10

Enumere el contenido del archivo tar de la siguiente manera:

tar tzf myarchive.tar

Luego, elimine esos nombres de archivo iterando sobre esa lista:

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

Esto seguirá enumerando los archivos que se eliminarán. Reemplace echocon rmsi está realmente seguro de que estos son los que desea eliminar. Y tal vez haga una copia de seguridad para estar seguro.

En una segunda pasada, elimine los directorios que quedan:

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

Esto evita que los directorios se eliminen si ya existían antes.


Otro buen truco de @glennjackman, que conserva el orden de los archivos, comenzando por los más profundos. Nuevamente, retírelo echocuando haya terminado.

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

Esto podría ser seguido por la rmdirlimpieza normal .

slhck
fuente
Extraña forma de escribir una pipa.
Stéphane Gimenez
Es no una tubería. Es la sustitución del proceso y prefiero esto sobre una tubería simple cuando se usa en combinación con whileun ciclo sobre un conjunto de registros. Me acabo de acostumbrar. @ sté
slhck
1
Perdón por la pequeña demora, noté que el uso rm -rfpodría eliminar archivos que no eran del archivo sino dentro de un directorio que tiene el mismo nombre que uno del archivo. Es mejor tener cuidado aquí y usar rmdiren un segundo pase.
Stéphane Gimenez
1
En realidad, el segundo paso con rmdirdebe ejecutarse para cada nivel de anidamiento de directorios. Por lo tanto, se limpiará subdir1en la primera pasada, pero abandone dir1ya que intentó eliminar esto primero cuando no estaba vacío en ese momento. Este comando podría ejecutarse una vez si la lista de archivos se puede ordenar en reversa.
Mike T
3
Si desea eliminar el en el orden inverso: tar tvf arch.tar | tac | xargs echo rm(elimine el eco cuando esté seguro)
Glenn Jackman
2

Aquí hay una posibilidad que tomará los archivos extraídos y los moverá a un subdirectorio, limpiando su carpeta 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";
    }

Guarde esto en el archivo fix-tar.ply luego ejecútelo así:

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

Esto confirmará que su tarlista es como la mía. Deberías obtener resultados como:

-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 eso se ve bien, ejecútelo nuevamente así:

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

El fixup.shscript serán los comandos de shell que moverán los archivos y directorios de nivel superior a una carpeta "limpia" (en este caso, la carpeta llamada cleanup). Eche un vistazo a este script para confirmar que todo es kosher. Si es así, ahora puedes limpiar tu desorden con:

$ sh fixup.sh

Prefiero este tipo de limpieza porque no destruye nada que no haya sido destruido al ser sobrescrito por esa inicial tar xv.

Nota: si esa salida inicial de ejecución en seco no se ve bien, debería poder manipular los números en las dos substrllamadas de función hasta que se vean correctamente. La $permsvariable se usa solo para la ejecución en seco, por lo que realmente solo la $direntsubcadena debe ser adecuada.

Otra cosa: es posible que deba usar la taropción --numeric-ownersi los nombres de usuario y / o nombres de grupo en la tarlista hacen que los nombres comiencen en una columna impredecible.

S2VpdGgA
fuente
1

Ese tipo de archivo (antisocial) se llama bomba de alquitrán debido a lo que hace. Una vez que uno de estos "explota" en usted, las soluciones en las otras respuestas son mucho mejores de lo que hubiera sugerido.

Sin embargo, la mejor "solución" es prevenir el problema en primer lugar.

La forma más fácil (más perezosa) de hacerlo es siempre descomprimir un archivo tar en un directorio vacío. Si incluye un directorio de nivel superior, simplemente lo mueve al destino deseado. Si no, simplemente cambie el nombre de su directorio de trabajo (el que estaba vacío) y muévalo a la ubicación deseada.

Si solo quiere hacerlo bien la primera vez, puede ejecutar tar -tvf archive-file.tar | menos y enumerará el contenido del archivo para que pueda ver cómo está estructurado y luego hacer lo necesario para extraerlo a la ubicación deseada para comenzar.

La opción t también es útil si desea inspeccionar el contenido de un archivo solo para ver si tiene algo que está buscando. Si lo hace, puede, opcionalmente, simplemente extraer los archivos que desee.

Joe
fuente