Удалите все файлы, которые не имеют следующие расширения в Linux - PullRequest
19 голосов
/ 27 декабря 2011

У меня есть список расширений:

avi,mkv,wmv,mp4,mp5,flv,M4V,mpeg,mov,m1v,m2v,3gp,avchd

Я хочу удалить все файлы без следующих расширений, а также файлы без расширений в каталоге в linux.

Как мне это сделать с помощью команды rm linux?

Ответы [ 3 ]

33 голосов
/ 27 декабря 2011

Сначала вам нужно будет найти файлы, которые не содержат это расширение. Вы можете сделать это очень легко с помощью команды find. Вы можете построить следующую команду -

find /path/to/files ! -name "*.avi" -type f -exec rm -i {} \;

Вы также можете использовать -regex вместо -name для подачи сложных шаблонов поиска. ! - чтобы отменить поиск. Таким образом, он будет эффективно перечислять те файлы, которые не содержат эти расширения.

Хорошо сделать rm -i, так как в нем будут перечислены все файлы перед удалением. Это может стать утомительным, если ваш список является исчерпывающим, поэтому вы сами можете включить его или нет.

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

Обновление:

Как указано в комментариях aculich, вы также можете сделать следующее -

find /path/to/files ! -name "*.avi" -type f -delete

-type f гарантирует, что он будет только find и delete обычных файлов и не будет касаться любых каталогов , ссылок sym и т. Д. .

12 голосов
/ 29 декабря 2011

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

Как и предлагали другие, вы можете использовать команду find. Я бы рекомендовал использовать find вместо rm почти во всех случаях.

Поскольку вы упоминаете, что находитесь в системе Linux, я буду использовать в своих примерах реализацию GNU , которая входит в пакет findutils , так как это значение по умолчанию в большинстве систем Linux и это то, что я обычно рекомендую изучать, поскольку он обладает гораздо более богатым и расширенным набором функций, чем многие другие реализации.

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

Найти пример

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

Перед удалением файлов я рекомендую предварительно просмотреть список файлов (или хотя бы часть списка, если он очень длинный):

find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$'

Приведенная выше команда покажет вам список файлов, которые вы будете удалять. Чтобы фактически удалить файлы, вы можете просто добавить действие -delete следующим образом:

find path/to/files -type f -regextype posix-extended -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$' -delete

Если вы хотите увидеть, что останется, вы можете инвертировать совпадения в предварительном просмотре, добавив ! к команде предварительного просмотра ( без * -delete) следующим образом:

find path/to/files -type f -regextype posix-extended ! -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$'

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

find path/to/files -type f
* * Объяснение тысячи сорок-девять

Здесь я подробно объясню варианты, которые я выбрал, и почему:

Я добавил -type f к ограничить совпадения только для файлов ; без этого он будет соответствовать не-файлам, таким как каталоги, которые вы, вероятно, не хотите. Также обратите внимание, что я ставлю это в начале, а не в конце, потому что порядок предикатов может иметь значение для скорости; сначала -type f выполняет проверку регулярных выражений только для файлов, а не для всего ... на практике это может не иметь большого значения, если у вас нет лотов каталогов или файлов. Тем не менее, стоит помнить порядок предикатов, поскольку в некоторых случаях это может оказать существенное влияние.

Я использую опцию без учета регистра -iregex, в отличие от опции -regex с учетом регистра, потому что я предполагал, что вы хотите использовать сопоставление без учета регистра, поэтому оно будет включать оба .wmv и .WMV файлов.

Возможно, вы захотите использовать расширение регулярных выражений POSIX для простоты и краткости. К сожалению, для -regextype posix-extended пока нет короткой руки, но я все равно рекомендовал бы использовать ее, потому что вы можете избежать проблемы с добавлением большого количества обратных слешей \, чтобы избежать более длинных, более сложных регулярных выражений, и он имеет более продвинутые (современные) функции. В реализации GNU по умолчанию используется регулярные выражения в стиле emacs , что может сбить с толку, если вы к ним не привыкли.

Опция -delete должна иметь очевидный смысл, однако иногда люди предлагают использовать более медленную и более сложную опцию -exec rm {} \;, но обычно это происходит потому, что они не знают о более безопасной, быстрой и простой опции -delete ( и в редких случаях вы можете встретить старые системы с древней версией find, у которой нет этой опции). Полезно знать, что -exec существует, но используйте -delete, где вы можете для удаления файлов. Кроме того, не передавайте | вывод find в другую программу, если вы не используете и не понимаете опцию -print0, в противном случае вы столкнетесь с огромной болью, когда столкнетесь с файлами с пробелами.

Аргумент path/to/files, который я включил явно. Если вы пропустите его, он будет неявно использовать . в качестве пути, однако безопаснее (особенно с -delete) явно указать путь.

Альтернативные реализации находок

Даже если вы сказали, что работаете в системе Linux, я также упомяну о различиях, с которыми вы столкнетесь при реализации BSD , в которую входит Mac OS X ! Для других систем (таких как старые версии Solaris), удачи! Обновите до одного из более современных find вариантов!

Основное различие в этом примере касается регулярных выражений. Варианты BSD по умолчанию используют базовые регулярные выражения POSIX. Чтобы избежать обременительного дополнительного экранирования в регулярных выражениях, необходимых для basic-PRE, вы можете воспользоваться более современными функциями расширенного PRE, указав опцию -E с вариантом BSD для достижения того же поведения, что и у варианта GNU, использующего -regextype posix-extended.

find -E path/to/files -iregex '.*\.(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)$' -type f

Обратите внимание, что в этом случае опция -E стоит до path/to/files, тогда как опция -regextype posix-extended для GNU идет после пути.

Жаль, что GNU пока не предоставляет опцию -E (пока!); так как я думаю, что было бы полезно иметь паритет с вариантами BSD, я отправлю патч на findutils, чтобы добавить эту опцию, и если он будет принят, я обновлю этот ответ соответствующим образом.

rm - Не рекомендуется

Хотя я настоятельно рекомендую не использовать rm, я приведу примеры того, как выполнить более или менее то, что конкретно задал ваш вопрос (с некоторыми оговорками).

Предполагая, что вы используете оболочку с синтаксисом Bourne (обычно это то, что вы найдете в системе Linux, которая по умолчанию используется в оболочке Bash), вы можете использовать эту команду:

for ext in avi mkv wmv mp4 mp5 flv M4V mpeg mov m1v m2v 3gp avchd; do rm -f path/to/files/*.$ext; done

Если вы используете Bash и включили расширенную глобализацию с помощью shopt -s extglob, тогда вы можете использовать Сопоставление с шаблоном с расширением имени файла :

rm -f path/to/files/*.+(avi|mkv|wmv|mp4|mp5|flv|M4V|mpeg|mov|m1v|m2v|3gp|avchd)

Расширенный синтаксис глобализации +(pattern-list) будет соответствовать одному или нескольким вхождениям данных шаблонов.

Однако я настоятельно рекомендую не использовать rm, потому что:

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

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

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

Хотелось бы, чтобы команда rm просто забыла о rm, потому что я могу вспомнить несколько мест, где я предпочел бы использовать rm вместо (даже древних реализаций) find.

4 голосов
/ 08 ноября 2014

С помощью Bash вы можете сначала включить параметр extglob:

$ shopt -s extglob

И сделать следующее:

$ rm -i! (*. avi | * .mkv | * .wmv | * .mp4)

...