52

Я извлек zip-файл в непустую папку. Zip-файл содержит множество файлов и глубокую иерархию, которые объединены с существующим деревом целевого каталога. Как я могу удалить файлы и каталоги, которые были созданы, разархивировав их, не уничтожив файлы и каталоги, которые уже были там? Конечно, у меня все еще есть zip-файл, который я слил, так что информация там.

5 ответов5

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
27

Ответ 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
    
11

С ключом -Z1 , unzip будет перечислять ровно один файл в строке (и ничего больше).

Таким образом, вы можете использовать

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 подавляет сообщения об ошибках, возникающие при попытке удалить непустые или ранее удаленные каталоги.


Связанные справочные страницы:

2

Вот еще более простое и безопасное (я думаю) решение

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

Что это делает: команда unzip с кавычками выдаст список того, что было в вашем исходном файле.

Затем zip -m будет использовать этот список, чтобы добавить add для каждого в getmeoutofhere.zip и удалить его из исходного каталога (поэтому теоретически он должен быть идентичен myoriginalfile.zip.

Недостатком является то, что unzip -lqq создаст дополнительный текст, даты, время, размер файла и т.д. Это приведет к тому, что zip -m выдаст сообщения об ошибках, но это не должно иметь никакого влияния (если только у вас нет маловероятного случая файла с таким же название).

Обратите внимание, что это не приведет к удалению каталогов, которые были созданы во время распаковки.

1

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

Вот простая ситуация.

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

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

Это также найдет некоторые каталоги, но rm оставит их в покое. С ними можно разобраться во втором проходе:

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

Все каталоги, которые были недавно изменены, были изменены с помощью почтового индекса. Если rmdir успешно удаляет их, это означает, что они пусты. Пустые каталоги, которые были затронуты zip, вероятно, были созданы им: т.е. пришли из архива. Мы не можем быть на 100% уверены. Возможно, что задание распаковки поместило некоторые файлы в существующий каталог, который был пустым.

Если 24-часовая гранулярность find недостаточно хороша для задания, поскольку файлы в дереве были изменены слишком недавно, то я бы затем подумал о чем-то простом: предположим, что задание распаковки ничего не поместило в существующие подкаталоги. То есть все, что было разархивировано, - это либо файл на верхнем уровне, либо новый подкаталог, которого раньше не было, который поэтому содержит только материал из zip-архива. Затем:

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

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

:%s/.*/"&"/

Затем объедините все это в большую строку:

:%j

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

Irm - rf<ESC>

Запустите строку под курсором как команду оболочки:

!!sh<Enter>

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

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

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