Desfazer bagunça de extração de arquivo tar

34

Acabei de desarmar um arquivo que produziu uma bagunça de arquivos no meu diretório arrumado. Por exemplo:

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

Eu estava esperando que o arquivo tar fosse organizado em uma única pasta (ou seja myarchive/), mas não era! Agora, tenho 190 arquivos e diretórios que vomitaram digitalmente o que era um diretório organizado. Esses arquivos não identificados precisam ser limpos.

Existe alguma maneira de "desfazer" isso e excluir os arquivos e diretórios que foram extraídos deste arquivo?


Obrigado pelas excelentes respostas abaixo. Em resumo , aqui está o que funciona com duas etapas (1) excluir arquivos e (2) excluir a estrutura de diretórios vazia na ordem inversa de compactação (para excluir primeiro os diretórios externos):

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

E ainda mais seguro, para visualizar uma execução a seco dos comandos anexando echodepois xargs.

Mike T
fonte
Eu acho que você pode listar os arquivos no arquivo morto e excluí-los do diretório atual, mas isso parece potencialmente destrutivo (dados que você deseja manter). Eu também não tenho idéia de como escrever um script bash, então não posso ajudar lá.
22412 Bob
Felizmente, nada foi substituído!
Mike T
Eu não sou do representante e tenho medo de parecer irritadiço, não importa como eu coloque isso, o que não sou (gostei também da resposta do slhck e fiz +1: ed, e honestamente: ± 15 rep é não é meu mundo), mas você acaba usando minha resposta sugerida com tubos e xargs(em tacvez de sort -rapenas cosméticos), mas aceita a resposta com substituição de processo que, como explicado nos comentários, não se encaixava em você? Além disso, indique a xargs -d'\n'opção em sua postagem se você quiser resumir para futuros usuários, para que eles não sejam mordidos por espaços nos nomes dos arquivos.
Daniel Andersson
@DanielAndersson, eu nunca entendi a necessidade -d'\n'até agora e, após uma análise mais aprofundada, sua resposta está realmente mais próxima do que eu usei.
Mike T
Totalmente bem com isso também, gostei da solução de @ Daniel :) A necessidade -d'\n'reside no fato de que, se você não disser xargspara dividir argumentos em novas linhas (que é o que você está alimentando), mas em espaços, um arquivo com o O nome folder1/some fileserá lido como folder1/somee name.
Slhck 16/05/12

Respostas:

36
tar tf archive.tar

irá listar o conteúdo linha por linha.

Isso pode ser canalizado xargsdiretamente, mas cuidado : faça a exclusão com muito cuidado. Você não quer apenas rm -rtudo o que tar tflhe diz, pois pode incluir diretórios que não estavam vazios antes de descompactar!

Você poderia fazer

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

para remover primeiro todos os arquivos que estavam no arquivo morto e, em seguida, os diretórios deixados em branco.

sort -r(glennjackman sugeriu, em tacvez de sort -rnos comentários da resposta aceita, que também funciona, já que tara saída é regular o suficiente) é necessária para excluir os diretórios mais profundos primeiro; caso contrário, um caso em que dir1contém um único diretório vazio dir2sairá dir1após a rmdirpassagem, desde que foi não esvaziar antes dir2foi removido.

Isso irá gerar muitos

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

e

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

Cale a boca com 2>/dev/nullisso, se isso o incomoda, mas eu preferiria manter o máximo de informações possível sobre o processo.

E não faça isso até ter certeza de que corresponde aos arquivos corretos. E talvez tente rm -iconfirmar tudo. E faça backups, tome seu café da manhã, escove os dentes, etc.

Daniel Andersson
fonte
Sim, seria melhor passar a -d'\n'opção para xargs.
Stéphane Gimenez 15/05
@slhck e Stéphane: Ah, sim, eu vou atualizar. Acabei de fazer um pequeno caso de teste, mas os arquivos não tinham espaços.
Daniel Andersson
11
Deve-se notar que o BSD xargsnão tem -d, então você precisa da variante GNU se você é uma alma pobre como eu.
Slhck 15/05
10

Liste o conteúdo do arquivo tar da seguinte maneira:

tar tzf myarchive.tar

Em seguida, exclua esses nomes de arquivos iterando sobre essa lista:

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

Isso ainda listará apenas os arquivos que seriam excluídos. Substitua echopor rmse tiver certeza de que esses são os que você deseja remover. E talvez faça um backup para ter certeza.

Em uma segunda passagem, remova os diretórios restantes:

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

Isso evita que os diretórios sejam excluídos, se eles já existiam antes.


Outro truque legal do @glennjackman, que preserva a ordem dos arquivos, começando pelos mais profundos. Mais uma vez, remova echoquando terminar.

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

Isso pode ser seguido pela rmdirlimpeza normal .

slhck
fonte
Maneira estranha de escrever um cachimbo.
Stéphane Gimenez
É não um cachimbo. É substituição de processo e eu prefiro isso ao invés de tubulação simples quando usada em combinação com whileloop sobre um conjunto de registros. Acostumei-me a isso. @ sté
slhck 15/05
11
Desculpe pelo pequeno atraso, notei que o uso rm -rfpoderia excluir arquivos que não eram do arquivo morto, mas dentro de um diretório com o mesmo nome que um arquivo. Melhor ter cuidado aqui e usar rmdirem um segundo passe.
Stéphane Gimenez 15/05
11
Na verdade, a segunda passagem rmdirprecisa ser executada para cada nível de aninhamento de diretórios. Portanto, ele será limpo subdir1na primeira passagem, mas saia, dir1pois tentou excluir essa primeira vez quando não estava vazia no momento. Este comando pode ser feito uma vez se a lista de arquivos puder ser classificada inversamente.
Mike T
3
Se você quiser excluir o na ordem inversa: tar tvf arch.tar | tac | xargs echo rm(remover o eco quando você está confiante)
Glenn Jackman
2

Aqui está uma possibilidade que pega os arquivos extraídos e os move para um subdiretório, limpando sua pasta 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";
    }

Salve isso no arquivo fix-tar.ple execute-o assim:

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

Isso confirmará que sua tarlista é como a minha. Você deve obter uma saída 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/

Se isso parecer bom, execute-o novamente assim:

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

O fixup.shscript serão os comandos do shell que moverão os arquivos e diretórios de nível superior para uma pasta "limpa" (nesse caso, a pasta chamada cleanup). Dê uma olhada neste script para confirmar que é tudo kosher. Se for, agora você pode limpar sua bagunça com:

$ sh fixup.sh

Prefiro esse tipo de limpeza porque não destrói nada que ainda não foi destruído por ser substituído por essa inicial tar xv.

Nota: se essa saída inicial de operação a seco não parecer correta, você poderá mexer nos números das duas substrchamadas de função até que pareçam adequadas. A $permsvariável é usada apenas para a execução a seco; portanto, apenas a $direntsubstring precisa ser adequada.

Outra coisa: você pode precisar usar a taropção --numeric-ownerse os nomes de usuário e / ou grupos na tarlista fizerem os nomes começarem em uma coluna imprevisível.

S2VpdGgA
fonte
1

Esse tipo de arquivo (anti-social) é chamado de bomba de alcatrão por causa do que faz. Depois que uma dessas "explode" em você, as soluções nas outras respostas são muito melhores do que o que eu teria sugerido.

A melhor "solução", no entanto, é evitar o problema em primeiro lugar.

A maneira mais fácil (mais preguiçosa) de fazer isso é sempre descompactar um arquivo tar em um diretório vazio. Se incluir um diretório de nível superior, basta movê-lo para o destino desejado. Caso contrário, renomeie seu diretório de trabalho (o que estava vazio) e mova-o para o local desejado.

Se você quiser acertar da primeira vez, execute tar -tvf archive-file.tar | menos e listará o conteúdo do arquivo, para que você possa ver como ele está estruturado e, em seguida, faça o necessário para extraí-lo para o local desejado.

A opção t também é útil se você deseja inspecionar o conteúdo de um arquivo apenas para ver se ele tem algo que você está procurando. Nesse caso, você pode, opcionalmente, apenas extrair o (s) arquivo (s) que deseja.

Joe
fonte