Скасувати безлад для вилучення файлу


34

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

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

Я очікував, що файл tar буде організований в одній папці (тобто myarchive/), але це не було! Зараз у мене є 190 файлів і каталогів, які в цифровому вигляді зафіксували те, що було організованим каталогом. Ці файли untar'd потрібно очистити.

Чи є спосіб "скасувати" це та видалити файли та каталоги, вилучені з цього архіву?


Дякуємо за чудові відповіді нижче. У підсумку , ось що працює з двома кроками (1) видалення файлів та (2) видалення порожньої структури каталогів у зворотному порядку упаковки (спочатку видалення зовнішніх каталогів):

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

І ще безпечніше попередній перегляд команд шляхом додавання echoпісля xargs.


Я думаю, ви могли б перерахувати файли в архіві та видалити їх із поточного каталогу, але це вважає потенційно руйнівними дані (дані, які ви хочете зберегти). Я також не маю уявлення, як написати баш-скрипт, тому я не можу там допомогти.
Боб

На щастя, нічого не перезаписали!
Майк Т

Я не після представника, і я боюся, що я прозвучу примхливо, незалежно від того, як я це ставлю, чого я не є (мені також сподобалась відповідь slhck, і я +1: редагував це, і чесно: ± 15 реп. не мій світ), але ви в кінцевому підсумку використовуєте запропоновану мною відповідь з допомогою труб і xargs( tacзамість цього sort -rє просто косметика), але ви приймаєте відповідь із заміною процесу, яка, як ви пояснили в коментарях, вам не підходила? Також, будь ласка, введіть xargs -d'\n'перемикач у своїй публікації, якщо ви хочете зробити підсумок для майбутніх користувачів, щоб вони не покусали пробіли у назвах файлів.
Даніель Андерссон

@DanielAndersson, я ніколи не розумів необхідності -d'\n'до цього часу, і після подальшого аналізу ваша відповідь насправді ближче до того, що я використовував.
Майк Т

Цілком добре з цим теж сподобалось рішення @ Даніеля :) Необхідність -d'\n'полягає в тому, що якщо ви не скажете xargsрозділяти аргументи на нові рядки (це те, що ви подаєте), а на пробіли, то файл з ім'я folder1/some fileбуде читатися як folder1/someі name.
slhck

Відповіді:


36
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все підтвердити. І мати резервні копії, їсти сніданок, чистити зуби тощо.


Так, було б краще передати -d'\n'варіант xargs.
Стефан Гіменез

@slhck та Stéphane: Ага, так, я оновлю. Я просто зробив невеликий тестовий випадок, але у файлах не було пробілів.
Даніель Андерссон

1
Слід зазначити, що BSD xargsне має -d, тому вам потрібен варіант GNU, якщо ви бідна душа, як я.
slhck

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очищення.


Дивний спосіб написання труби.
Стефан Гіменез

Це не труба. Це підміна процесу, і я віддаю перевагу цьому над простими трубопроводами, коли вони використовуються в поєднанні з whileциклом на набір записів. Просто звик до цього. @ sté
slhck

1
Вибачте за невелику затримку, я помітив, що за допомогою rm -rfможна видалити файли, які були не з архіву, а всередині каталогу, який має те саме ім'я, що і один з архіву. Тут краще бути обережним і використовувати rmdirв другому проході.
Стефан Гіменез

1
Насправді другий пропуск rmdirповинен бути виконаний для кожного рівня введення каталогів. Таким чином, він очиститься subdir1під час першого проходу, але вийдіть, dir1оскільки він спробував видалити цей перший, коли він ще не був порожнім. Ця команда може бути виконана один раз, якщо список файлів може бути відтворений у зворотному порядку.
Майк Т

3
Якщо ви хочете видалити в зворотному порядку: tar tvf arch.tar | tac | xargs echo rm(видаліть ехо, коли ви впевнені)
glenn jackman

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 -tvf archive-file.tar | менше, і він перелічить вміст архіву, щоб ви могли бачити, як він структурований, а потім зробите все, що потрібно, щоб добути його до потрібного місця для початку.

Варіант t також стане в нагоді, якщо ви хочете перевірити вміст архіву, щоб побачити, чи є в ньому щось, що ви шукаєте. Якщо це так, ви можете, за бажанням, просто витягнути потрібний файл.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.