знайти -exec cmd {} + vs | xargs


115

Який із них є більш ефективним для дуже великого набору файлів і його слід використовувати?

find . -exec cmd {} +

або

find . | xargs cmd

(Припустимо, що у назви файлів немає смішних персонажів)


Відповіді:


107

Різниця швидкостей буде незначною.

Але ви повинні переконатися, що:

  1. Ваш сценарій не передбачає, що жоден файл не матиме місця, вкладки тощо у назві файлу; перша версія безпечна, друга - ні.

  2. Ваш сценарій не буде розглядати файл, який починається з " -" як опцію.

Отже, ваш код повинен виглядати так:

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

або

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

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


4
-print0 - це також опція пошуку GNU (та xNGGN GNU), якої не вистачає у багатьох системах, що не є Linux, тому аргумент портативності не є таким, що є дійсним. Однак використання просто -друку та відключення x0 від xargs є дуже портативним.
dannysauer

7
Справа в тому, що без -print0 він не працює, якщо є файл з пробілом або вкладкою і т. Д. Це може бути вразливістю безпеки, ніби є ім'я файлу типу "foo -o index.html", тоді -o буде оброблятися як варіант. Спробуйте в порожньому каталозі: "touch - foo \ -o \ index.html; find. | Xargs cat". Ви отримаєте: "cat: недійсний варіант -" o ""
Tometzky

2
Його приклад - ім'я файлу, яке містить -. Без -print0, знахідка виплюне ./foo -o index.html. Тож, можливо, починати з - це не велика справа, але результат мало змінений, і в системі багатокористувача може бути вектор атаки, якщо ваш сценарій читається у всьому світі.
bobpaul

2
Зауваження про те, що мене тут спонукало - використання execбуде видавати результати, коли вони знайдені, xargsколи, схоже, буде чекати, поки весь каталог буде шуканий, перш ніж писати в stdout. Якщо ви намагаєтеся це у великому каталозі, і здається, що xargsце не працює, терпіння доцільно.
FarmerGedden

1
@Motivate Без -print0пошуку повертає назви файлів, розділені новим рядком, але новий рядок також може бути частиною імені файлу, що робить його неоднозначним. Байт 0 не може, тому це безпечний роздільник. Так - додавання --до команди, яка його підтримує, є хорошою практикою, коли ви не можете контролювати її аргументи, навіть якщо це не завжди суворо потрібно або небезпечно.
Томецький

7
find . | xargs cmd

є більш ефективним (він працює cmdяк можна менше разів, на відміну від exec, який працює cmdодин раз на кожен матч). Однак у вас виникнуть проблеми, якщо в назви файлів містяться пробіли або фанкі.

Пропонується використовувати наступне:

find . -print0 | xargs -0 cmd

це буде працювати, навіть якщо назви файлів містять фанкі ( -print0змушує findдрукувати збіги, що закінчуються NUL, -0змушує xargsочікувати цього формату).


28
Це не "find. -Exec cmd {} \;" але "знайти. -exec cmd {} +". Останній не запускатиме по одному файлу одночасно.
Томецький

2
Зауважте, що xargsпідхід насправді значно повільніший, якщо немає (або лише декілька) відповідних файлів і cmdне має багато що робити для кожного файлу. Наприклад, при запуску в порожньому каталозі xargsверсія займе щонайменше вдвічі більше часу, оскільки два процеси потрібно запустити замість лише одного. (Так, різниця, як правило, непомітна для * nix, але в циклі це може бути важливо; або спробуйте це в Windows деякий час ...)
SamB,

2

Сучасні xargsверсії часто підтримують паралельне виконання трубопроводу.

Очевидно, що це може бути точками зрізу, коли мова йде про вибір між find … -exec та … | xargs

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.