31

Я просто распаковал архив, который создал беспорядок в моем аккуратном каталоге. Например:

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

Я ожидал, что tar-файл будет организован в одну папку (т.е. myarchive/), но это не так! Теперь у меня есть около 190 файлов и каталогов, которые в цифровом виде оказались в том, что было организованным каталогом. Эти неиспользуемые файлы необходимо очистить.

Есть ли способ "отменить" это и удалить файлы и каталоги, которые были извлечены из этого архива?


Спасибо за отличные ответы ниже. Таким образом, вот что работает с двумя шагами (1) удаление файлов и (2) удаление пустой структуры каталогов в обратном порядке упаковки (чтобы сначала удалить внешние каталоги):

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

И еще безопаснее - предварительно просмотреть пробные команды, добавив echo после xargs .

4 ответа4

34
tar tf archive.tar

будет перечислять содержимое построчно.

Это может быть напрямую передано в xargs , но будьте осторожны: делайте удаление очень осторожно. Вы не хотите просто использовать rm -r всего, что сообщает tar tf , поскольку оно может содержать каталоги, которые не были пусты перед распаковкой!

Вы могли бы сделать

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

сначала удалить все файлы, которые были в архиве, а затем каталоги, которые остались пустыми.

sort -r (glennjackman предложил tac вместо sort -r в комментариях к принятому ответу, что также работает, поскольку вывод tar достаточно регулярный) необходим для удаления наиболее глубоких каталогов; в противном случае случай, когда dir1 содержит один пустой каталог, dir2 покинет dir1 после прохода rmdir , поскольку он не был пуст до удаления dir2 .

Это создаст много

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

а также

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

Закройте это с помощью 2>/dev/null если это вас раздражает, но я бы предпочел сохранить как можно больше информации о процессе.

И не делайте этого до тех пор, пока вы не будете уверены, что вы подбираете нужные файлы. И, возможно, попробуйте rm -i чтобы подтвердить все. И делайте резервные копии, завтракайте, чистите зубы и т.д.

10

Перечислите содержимое файла tar следующим образом:

tar tzf myarchive.tar

Затем удалите эти имена файлов, повторяя этот список:

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

Это по-прежнему будет просто список файлов, которые будут удалены. Замените echo на rm если вы действительно уверены, что это те, которые вы хотите удалить. И, возможно, сделать резервную копию, чтобы быть уверенным.

Во втором проходе удалите оставшиеся каталоги:

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

Это предотвращает удаление каталогов с, если они уже существовали ранее.


Еще один приятный трюк @glennjackman, который сохраняет порядок файлов, начиная с самых глубоких. Снова удалите echo когда закончите.

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

Затем может последовать обычная очистка rmdir .

2

Вот возможность, которая возьмет извлеченные файлы и переместит их в подкаталог, очистив основную папку.

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

Сохраните это в файл fix-tar.pl а затем выполните его так:

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

Это подтвердит, что ваш список tar похож на мой. Вы должны получить вывод как:

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

Если это выглядит хорошо, запустите его снова так:

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

Сценарий fixup.sh будет представлять собой команды оболочки, которые будут перемещать файлы и каталоги верхнего уровня в "чистую" папку (в данном случае это папка с именем cleanup). Посмотрите этот скрипт, чтобы убедиться, что он кошерный. Если это так, теперь вы можете убрать беспорядок с помощью:

$ sh fixup.sh

Я предпочитаю такую очистку, потому что она не уничтожает ничего, что еще не было уничтожено перезаписью этой первоначальной tar xv .

Примечание: если этот исходный результат пробного прогона не выглядит правильным, вы должны иметь возможность играть с числами в двух вызовах функции substr пока они не будут выглядеть правильно. Переменная $perms используется только для пробного прогона, поэтому в действительности должна быть правильной только подстрока $dirent .

Еще одна вещь: вам может понадобиться использовать опцию tar --numeric-owner если имена пользователей и / или имена групп в списке tar приводят к тому, что имена начинаются в непредсказуемом столбце.

1

Такого рода (антиобщественный) архив называют «бомбой-смолой» из-за того, что он делает. Как только один из них "взорвется" на вас, решения в других ответах будут намного лучше, чем я бы предложил.

Лучшее "решение", однако, состоит в том, чтобы предотвратить проблему в первую очередь.

Самый простой (самый ленивый) способ сделать это - всегда распаковывать архив tar в пустой каталог. Если он включает в себя каталог верхнего уровня, то вы просто перемещаете его в нужное место назначения. Если нет, просто переименуйте ваш рабочий каталог (тот, который был пустым) и переместите его в нужное место.

Если вы просто хотите сделать все правильно с первого раза, вы можете запустить tar -tvf archive-file.tar | меньше, и он будет перечислять содержимое архива, чтобы вы могли увидеть, как он структурирован, а затем сделать то, что необходимо, чтобы извлечь его в нужное место для начала.

Опция t также пригодится, если вы хотите просмотреть содержимое архива, просто чтобы посмотреть, есть ли в нем что-то, что вы ищете. Если это так, вы можете, при желании, просто извлечь нужные файлы.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .