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

30

Eu apenas descompactei um arquivo que produziu uma confusão de arquivos em meu diretório limpo. Por exemplo:

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

Eu esperava que o arquivo tar fosse organizado em uma única pasta (ou seja, myarchive/ ), mas não foi! Agora eu tenho cerca de 190 arquivos e diretórios que foram exibidos digitalmente no que era um diretório organizado. Esses arquivos com untar 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 dois passos (1) excluir arquivos e (2) excluir estrutura de diretório vazia na ordem de empacotamento reversa (para excluir diretórios externos primeiro):

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

E mais seguro ainda, para visualizar uma execução a seco dos comandos anexando echo após xargs .

    
por Mike T 15.05.2012 / 13:59

4 respostas

33
tar tf archive.tar

listará o conteúdo linha por linha.

Isso pode ser canalizado para xargs diretamente, mas beware : faça a exclusão com muito cuidado. Você não quer apenas rm -r de tudo o que tar tf informa, pois pode incluir diretórios que não estavam vazios antes de serem descompactados!

Você poderia fazer

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

primeiro remova todos os arquivos que estavam no arquivo e, em seguida, os diretórios que estão vazios.

sort -r (glennjackman sugeriu tac em vez de sort -r nos comentários para a resposta aceita, que também funciona, pois a saída de tar é regular o suficiente) é necessária para excluir os diretórios mais profundos primeiro; caso contrário, um caso em que dir1 contenha um único diretório vazio dir2 deixará dir1 após o rmdir pass, já que ele não estava vazio antes que dir2 fosse removido.

Isso gerará muito

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

e

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

Encerre isso com 2>/dev/null se isso te incomodar, mas prefiro 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 -i para confirmar tudo. E faça backups, coma seu café da manhã, escove os dentes, etc.

    
por 15.05.2012 / 14:15
10

Relacione o conteúdo do arquivo tar da seguinte forma:

tar tzf myarchive.tar

Em seguida, exclua esses nomes de arquivo por iteração na lista:

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

Isto irá apenas listar os arquivos que seriam deletados. Substitua echo por rm se 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 impede que os diretórios sejam excluídos se já existiam antes.

Outro truque legal do @glennjackman, que preserva a ordem dos arquivos, começando pelos mais profundos. Novamente, remova echo quando terminar.

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

Isso pode ser seguido pela limpeza rmdir normal.

    
por 15.05.2012 / 14:06
2

Aqui está uma possibilidade que pegará os arquivos extraídos e os moverá 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 este arquivo fix-tar.pl e execute-o assim:

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

Isso confirmará que sua lista tar é 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 script fixup.sh será os comandos shell que moverão os arquivos e diretórios de nível superior para uma pasta "limpa" (nesta instância, a pasta chamada cleanup ). Dê uma olhada neste script para confirmar que tudo é kosher. Se for, você pode agora limpar sua bagunça com:

$ sh fixup.sh

Eu prefiro esse tipo de limpeza porque ele não destrói nada que já não tenha sido destruído ao ser substituído por esse% inicial tar xv .

Nota: se essa saída inicial de execução a seco não parecer correta, você poderá manipular os números nas duas chamadas de função substr até que pareçam adequadas. A variável $perms é usada apenas para a execução a seco, portanto, apenas a $dirent de substring precisa ser adequada.

Uma outra coisa: pode ser necessário usar a tar option --numeric-owner se os nomes de usuários e / ou grupos na lista tar fizerem os nomes começarem em uma coluna imprevisível.

    
por 15.05.2012 / 15:59
1

Esse tipo de arquivo (anti-social) é chamado de bomba de alcatrão por causa do que faz. Uma vez que um desses "exploda" em você, as soluções nas outras respostas são muito melhores do que eu sugeriria.

A melhor "solução", no entanto, é prevenir 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 ele incluir um diretório de nível superior, mova-o para o destino desejado. Caso contrário, basta renomear seu diretório de trabalho (aquele que estava vazio) e movê-lo para o local desejado.

Se você quer apenas acertar na primeira vez, você pode executar tar -tvf archive-file.tar | less e listará o conteúdo do arquivo para que você possa ver como ele está estruturado e, em seguida, faça o que for necessário para extraí-lo no local desejado para começar.

A opção t também é útil se você quiser inspecionar o conteúdo de um arquivo apenas para ver se há algo que você está procurando nele. Em caso afirmativo, você pode, opcionalmente, apenas extrair o (s) arquivo (s) desejado (s).

    
por 27.05.2012 / 21:25