Як "невитягнути" поштовий файл?


52

Я витягнув zip-файл у не порожню папку. У zip-файлі є безліч файлів і глибока ієрархія, що об'єдналися з існуючим деревом цільового каталогу. Як я можу видалити файли та каталоги, що там, де створено розпакуванням, не знищуючи файли та каталоги, які вже були там? Звичайно, у мене ще є zip-файл, в який я об'єднався, тому інформація є.


Хм дякую за прийняття, але це була ідея @ jjin. Я не знав lqваріантів unzizp, я просто додав кілька класичних прийомів * nix навколо його головної відповіді.
тердон

Це добре, мене це не дуже хвилює. Я додав свою власну іншу версію обробки пробілів.
jjlin

@terdon Так ... Я також підтримав відповідь jjlin, але я можу прийняти лише одну відповідь.
mafp

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

@Joe У цьому є своє використання. Пакети LaTeX, наприклад, можуть надходити у foo.tds.zipформі. Ці блискавки зливаються у дерево TEXMF, що дуже зручно. Але якщо ви коли-небудь захочете видалити такий пакет, ви стикаєтесь з описаною вами проблемою.
mafp

Відповіді:


28

Відповідь jjlin - це шлях. Я просто хочу додати кілька варіантів для каталогів:

  • Видаліть усі витягнуті файли, не маючи каталогів :

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done
  • Видаліть лише витягнуті файли та порожні каталоги

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm "$n"; done; rmdir *

    Без жодних параметрів, rmdirвидаляє лише порожні каталоги, вони залишать файли та непорожні папки в спокої, щоб ви могли безпечно запускати його *.

  • Видаліть усе витягнуте, але підкажіть підтвердження перед кожним видаленням:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -ri "$n"; done; rmdir *

    -iПрапор змусить rmпідказувати перед кожним видаленням, ви можете вибрати Так або Ні

  • Видаліть все витягнуте, включені каталоги:

    unzip -lqq file.zip | gawk -F"  " '{print $NF;}' |
      while IFS= read -r n; do rm -rf "$n"; done

Видалення порожніх каталогів легко виконати за допомогою find: find * -depth -type d -exec rmdir {} +і проігнорувати всі Directory not emptyповідомлення. Може бути законним скоротити це значення, find * -type d -deleteоскільки -deleteпараметр вмикається, -depthале я не перевірив, що -deleteне видалятиме не порожній каталог.
Адріан Пронк

@AdrianPronk це не так:find: cannot delete './foo': Directory not empty
terdon

28

Ви можете використовувати unzip -lqq <filename.zip>для списку вмісту zip-файлу; це буде включати деяку сторонні дані, які вам потрібно буде відфільтрувати. Ось команда, яка працює для мене:

unzip -lqq file.zip | awk '{print $4;}' | xargs rm -rf

У awkкоманді витягує тільки імена файлів і каталогів. Потім результат передається, xargsщоб видалити все. Я пропоную виконати команду в сухому режимі (тобто, опустивши xargs rm -rfчастину), щоб переконатися, що результати правильні.

Вищевказана команда матиме проблеми, що стосуються шляхів, які мають пробіл. Ця (більш складна) версія повинна виправити:

unzip -lqq file.zip | awk '{$1=$2=$3=""; sub(/ */, "", $0); printf "%s%s", $0, "\0"}' | xargs -0 rm -rf

Це вже досить близько до того, що я мав на увазі, але unzip -lqqперераховує також каталоги, що містяться в zip. Поки що я б відпустив усі каталоги на самоті. Як видалити всі порожні каталоги в дереві, може бути додатковим питанням.
mafp

@mafp Це хороший момент про каталоги. Ви можете додати grep -v '/$'в конвеєр, щоб пропустити видалення каталогів (у всіх яких є косою косою рискою, AFAICT).
jjlin

@terdon Насправді я думаю, що проблема починається з того awk, що , якщо надрукувати всього 4 долари не буде надруковано повний шлях.
jjlin

Я не думаю, що ви повинні використовувати -rопцію rm: це, здається, викликає проблеми, особливо в поєднанні з цим -fпараметром. Я б взагалі не використовував цю -fопцію в цьому сценарії.
Адріан Пронк

1
@jjlin: grep -v '/$'опускати лише записи каталогів у ZIP-файлі. Вони все ще включатимуть записи, які були звичайними файлами у ZIP-файлі, але були попередніми каталогами в цільовій папці. З цієї причини було б розумно опустити-r
Адріан Пронк

11

За допомогою перемикача -Z1разархівуйте список одного файлу в кожному рядку (і нічого іншого).

Таким чином, ви можете використовувати

unzip -Z1 | xargs -I {} rm '{}'

видалити всі файли, витягнуті з zip-файлу.

Команда

unzip -Z1 | xargs -I {} rm -rf '{}'

також буде видалено каталоги, але ви повинні бути обережними. Якщо каталоги вже існували до вилучення zip-файлу, всі попередні файли в цих каталогах також буде видалено.


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

Спочатку витягніть zip-файл, куди ви спочатку мали намір витягнути його:

unzip file.zip -d elsewhere

Тепер перейдіть до каталогу, де ви вилучили файли помилково, і виконайте таку команду:

find elsewhere -type f -printf "%P\0" | xargs -0 -I {} rm '{}'
  • -type f знаходить лише файли (без каталогів).

  • %P\0- відносний шлях (без elsewhere/), за яким слідує нульовий символ.

  • -0робить xargs окремими рядками нульовими символами. Це більш надійно, оскільки - теоретично - імена файлів можуть містити символи нового рядка.


Для роботи з каталогами, що залишилися, ви можете виконати команду:

find -type d -exec rmdir -p {} \; 2> /dev/null
  • -type d знаходить лише каталоги.

  • -exec rmdir -p {} \;виконує rmdir -p {}для кожного знайденого каталогу.

    {}це знайдений каталог, і -pперемикач змушує rmdir також видаляти свої порожні батьківські каталоги.

  • 2> /dev/null пригнічує повідомлення про помилки, які виникатимуть при спробі видалити непорожні або раніше видалені каталоги.


Пов'язані чоловічі сторінки:


+1 для того, щоб змусити мене читати zipinfoсторінку чоловіка.
тердон

Ну, о, це трохи полегшує. :)
jjlin

2

Ось ще простіше і безпечніше (я думаю) рішення

zip -m getmeoutofhere.zip `unzip -lqq myoriginalzipfile.zip`
rm getmeoutofhere.zip

Що це робить: Команда unzip із зворотним цитуванням створить список того, що було у вашому вихідному файлі.

zip -m потім використовуватиме цей список, щоб додати, що кожен до getmeoutofhere.zip та видалить його з оригінального каталогу (так теоретично він повинен бути вказівним до myoriginalfile.zip.

Мінус полягає в тому, що unzip -lqq створить додатковий текст, дати, час, розмір файлів тощо. Це призведе до отримання zip -m повідомлень про помилки, але це не повинно впливати (якщо ви не маєте ймовірного випадку файлу з тим самим назва).

Зауважте, що це не видалить жодних каталогів, створених під час оригінального розпакування.


Цікавий підхід, вивчимо далі.
mafp

1

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

Ось проста ситуація.

Припустимо, що жоден із існуючих файлів у поточному каталозі не торкався принаймні 24 години. Тому все, що було змінено протягом останніх 24 годин, є сміттям із zipfile.

$ find . -mtime -1 -print0 | xargs -0 rm

Тут знайдуться і деякі каталоги, але rmвони залишать їх у спокої. З ними можна вирішити другий прохід:

$ find . -mtime 1 -type d -print 0 | xargs -0 rmdir

Будь-які каталоги, які були нещодавно модифіковані, були модифіковані за допомогою zip. Якщо їх rmdirуспішно видаляє, це означає, що вони порожні. Порожні каталоги, які торкалися zip, ймовірно, були створені ним: тобто надходили з архіву. Ми не можемо бути на 100% впевнені. Можливо, що розпаковане завдання помістило деякі файли в існуючий каталог, який був порожнім.

Якщо find24-годинна деталізація недостатньо хороша для роботи, оскільки файли в дереві були модифіковані занадто недавно, то я б розглядав щось просте: припустимо, що розпаковане завдання нічого не помістило в існуючі підкаталоги. Тобто, все, що було розпаковано, - це або файл на верхньому рівні, або новий підкаталог, якого раніше не було, що, отже, не містить нічого, крім матеріалу з zip. Тоді:

# list directory in descending order of modification time
$ ls -1t > filelist  # descending order of modification time

Тепер ми відкриваємося filelistв текстовому редакторі та визначаємо перший запис у списку, який не прийшов із zip. Ми видаляємо цей запис та все інше після нього. Залишилися файли та каталоги, які надійшли з блискавки. Спочатку ми візуально перевіряємо на предмет таких питань, як пробіли в іменах та виникнення лапок, які потрібно уникнути. Потім ми можемо додавати цитати навколо всього, якщо потрібно: Наступне передбачає, що ви використовуєте Vim:

:%s/.*/"&"/

Потім приєднайте все це до великої лінії:

:%j

Тепер вставити rm -rfперед ним:

Irm - rf<ESC>

Запустіть рядок під курсором у вигляді команди оболонки:

!!sh<Enter>

Безумовно, я б не автоматизував кроки цього завдання через ризик стерти файли, які вже були там, або перекрутити через проблеми з іменем файлу.

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

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