find -exec cmd {} + vs | xargs

115

Какой из них более эффективен для очень большого набора файлов и должен использоваться?

find . -exec cmd {} +

или

find . | xargs cmd

(Предположим, что в именах файлов нет забавных символов)

кендырь
источник
Связанный: stackoverflow.com/questions/9612090/…
Mateusz Piotrowski

Ответы:

107

Разница в скорости будет незначительной.

Но вы должны убедиться, что:

  1. Ваш сценарий не будет предполагать, что в имени файла не будет места, табуляции и т.д. первая версия безопасна, вторая нет.

  2. Ваш сценарий не будет рассматривать файл, начинающийся с " -", как вариант.

Итак, ваш код должен выглядеть так:

find . -exec cmd -option1 -option2 -- {} +

или

find . -print0 | xargs -0 cmd -option1 -option2 --

Первая версия короче и проще для написания, так как вы можете игнорировать 1, но вторая версия более переносима и безопасна, поскольку " -exec cmd {} +" является относительно новой опцией в GNU findutils (с 2005 года во многих работающих системах ее еще нет) и он недавно был глючен . Также многие люди не знают этого " -exec cmd {} +", как вы можете видеть из других ответов.

Tometzky
источник
4
-print0 - это также опция GNU find (и GNU xargs), которая отсутствует во многих системах, отличных от Linux, поэтому аргумент переносимости не так допустим. Использование только -print и оставив -0 офф xargs, однако, является очень компактен.
dannysauer
7
Дело в том, что без -print0 он не работает, если есть файл с пробелом или табуляцией и т. Д. Это может быть уязвимость безопасности, как если бы имя файла вроде "foo -o index.html", то -o будет обработано как вариант. Попробуйте в пустом каталоге: "touch - foo \ -o \ index.html; find. | Xargs cat". Вы получите: «cat: invalid option - 'o'»
Томецкий
2
Его пример - имя файла, содержащее -. Без -print0 find выдаст ./foo -o index.html. Так что, возможно, начать с - не имеет большого значения, но результат немного изменился, и в многопользовательской системе может обеспечить вектор атаки, если ваш сценарий доступен для чтения всем.
bobpaul 02
2
Замечание о том, что меня здесь execсбило с толку - использование будет выводить результаты по мере их нахождения, тогда xargsкак, похоже, будет ждать, пока не будет проведен поиск по всему каталогу, прежде чем писать в стандартный вывод. Если вы пробуете это сделать с большим каталогом, и вам кажется, что xargsэто не работает, рекомендуется набраться терпения.
FarmerGedden
1
@Motivated Без -print0find возвращает имена файлов, разделенные символом новой строки, но новая строка также может быть частью имени файла, что делает его неоднозначным. Байт 0 не может, поэтому это безопасный разделитель. Да - добавление --к команде, которая поддерживает эту функцию, является хорошей практикой, когда вы не можете контролировать ее аргументы, даже если это не всегда строго требуется или небезопасно.
Tometzky
7
find . | xargs cmd

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

Предлагается использовать следующее:

find . -print0 | xargs -0 cmd

это будет работать, даже если имена файлов содержат забавные символы ( -print0делает findвывод совпадений, заканчивающихся NUL, -0заставляет xargsожидать этот формат.)

Просить
источник
28
Это не "find. -Exec cmd {} \;" но "найти. -exec cmd {} +". Последний не будет запускать по одному файлу за раз.
Tometzky
2
Обратите внимание, что этот xargsподход на самом деле значительно медленнее, если нет (или всего несколько) совпадающих файлов, и cmdдля каждого файла не нужно много делать. Например, при запуске в пустом каталоге xargsверсия займет как минимум в два раза больше времени, так как нужно запустить два процесса вместо одного. (Да, разница обычно незаметна на * nix, но в цикле это может быть важно; или, попробуйте когда-нибудь в Windows ...)
SamB
2

xargsВерсии Modern часто поддерживают параллельное выполнение конвейера.

Очевидно, это может быть поворотный момент, когда дело доходит до выбора между find … -exec и … | xargs

Poige
источник