Wiki
Clone wikicomp-house.repo / abuse-find-exec
Как делать не надо
Некоторые несознательные товарищи склоняют общественность к использованию опции -exec и даже -delete в команде find.
http://linuxaria.com/howto/linux-shell-how-to-use-the-exec-option-in-find-with-examples?lang=en
вот что предлагается:
Some examples with find and exec find / -name "*.old" -exec /bin/rm {} \; find / -size +100M -exec /bin/rm {} \; find . -exec /bin/rm {} \; Please note, that you should NOT use these examples, In case of deletion of a file GNU find has the option -delete which is safer then “-exec /bin/rm {} ;”. For example: find / -name "*.old" -delete In older Unix system you could not have the -delete option, and so you have no choice but to use the -exec action. find ./ -type f -exec chmod 644 {} \; find / -user olduser -type f -exec chown newuser {} \; find . -type d -exec chmod 755 {} \;
Все это крайне неполезно по следующим причинам:
- Опция exec присутствует не во всех сборках find. Это скорее небольшой недостаток, чем проблема, тем не менее, что есть, то есть, так что не удивляйтесь, если в один прекрасный день сев за чужой компьютер, вы увидите вместо результата ошибку.
- Вам придется экранировать все спец-символы в команде. Даже если ничего такого у вас нет, обратите внимание на обратный слеш перед ; в конце каждого примера.
- Команда -exec будет исполняться отдельно для каждого аргумента. Удаление тысячи файлов породит тысячу запусков bash, что приводит к ужасающе долгому исполнению команды в целом. Правда, оказывается есть решение, использовать \+ вместо \; . В этом случае find сформирует список и передаст его в команду. Но что будет, если длина этого списока окажется больше, чем максимальная длина командной строки?
- Что будет, если в именах обрабатываемых файлов есть пробелы? Правильно, в лучшем случае будет no such file по нескольку раз на каждое такое имя. В худшем, если имена совпадут, будут удалены совершенно посторонние файлы.
Как это делать правильно? Альтернатива?
Использовать в паре с find утилиту хargs.
Первый же пример будет теперь выглядеть вот так:
find / -name "*.old" | xargs rm
Как видите, все гораздо проще. Теперь xargs берет список файлов от утилиты find и создает команду удаления сразу всего списка. Если число файлов превысит возможности вашей системы, xargs автоматически разобъет команду на несколько частей. Естественно, этим можно управлять.
Все хорошо, но осталась проблема с именами файлов с пробелами. Исправим ее:
find / -name "*.old" -print0 | xargs -0 rm
Все, теперь, когда мы попросили find использовать в качестве разделителя символ NULL, а xargs его принимать, как разделитель, все имена файлов будут переданы и распознаны как надо.
Updated