Я извлек zip-файл в непустую папку. Zip-файл содержит множество файлов и глубокую иерархию, которые объединены с существующим деревом целевого каталога. Как я могу удалить файлы и каталоги, которые были созданы, разархивировав их, не уничтожив файлы и каталоги, которые уже были там? Конечно, у меня все еще есть zip-файл, который я слил, так что информация там.
5 ответов
Вы можете использовать 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
Ответ 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
С ключом -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
подавляет сообщения об ошибках, возникающие при попытке удалить непустые или ранее удаленные каталоги.
Связанные справочные страницы:
Вот еще более простое и безопасное (я думаю) решение
zip -m getmeoutofhere.zip `unzip -lqq myoriginalzipfile.zip`
rm getmeoutofhere.zip
Что это делает: команда unzip с кавычками выдаст список того, что было в вашем исходном файле.
Затем zip -m будет использовать этот список, чтобы добавить add для каждого в getmeoutofhere.zip и удалить его из исходного каталога (поэтому теоретически он должен быть идентичен myoriginalfile.zip.
Недостатком является то, что unzip -lqq создаст дополнительный текст, даты, время, размер файла и т.д. Это приведет к тому, что zip -m выдаст сообщения об ошибках, но это не должно иметь никакого влияния (если только у вас нет маловероятного случая файла с таким же название).
Обратите внимание, что это не приведет к удалению каталогов, которые были созданы во время распаковки.
Если вы извлекли файлы так, что метка времени изменения в архиве не сохраняется в извлеченных копиях (а извлеченные файлы имеют обычное время модификации), то правильный способ атаковать это - время модификации. Все извлеченные файлы имеют более новую временную метку модификации, чем последний измененный существующий файл в этом каталоге.
Вот простая ситуация.
Предположим, что ни один из существующих файлов в текущем каталоге не был затронут в течение как минимум 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-архиве, запишите его в файл, внимательно его просмотрите и преобразуйте в удаление после выполнения любого необходимого редактирования.