знайти: відсутній аргумент до -exec


18

Я намагаюся запустити таку команду:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

Це повертає помилку:

find: missing argument to -exec

Я не бачу, що з цією командою не так, як це здається, відповідає тій самій сторінці:

команда -exec {} +

Цей варіант параметра -exec виконує вказану команду для вибраних файлів, але командний рядок будується додаванням кожного вибраного імені файлу в кінці; загальна кількість викликів команди буде значно меншою, ніж кількість відповідних файлів. Командний рядок побудований приблизно так само, як xargs будує свої командні рядки. У межах команди допускається лише один екземпляр "{}". Команда виконується в початковому каталозі.

Я також спробував:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+

Ви намагалися втекти +в кінці? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren

3
Можливо, ви використовуєте стару версію GNU find. Хоча -exec cmd {} +варіант є POSIX і доступний з 80-х років, GNU виявив, що додав його (відносно) недавно (2005 р.). Що find --versionвам каже?
Стефан Шазелас

2
@Koveras, це було б тоді. -exec {} +Додано в 4.2.12 в 2005 р. У старих знахідках GNU ви можете використовувати (non-POSIX), -print0 | xargs -r0щоб отримати щось подібне. 4.1від 1994 р.
Стефан Шазелас

1
JRFerguson вказав (у відповіді , який був вилучений) , що -nameаргументи моделі повинні бути вказані: -name "*.c" -o -name "*.h". Це правда, хоча це не пов’язано з -execпомилкою. Ви помітите, що всі інші відповіді ставлять підказки цитатами, хоча лише Гілз згадує про це. … (Продовжував)
G-Man каже: «Відновити Моніку»

1
(Протяг)… Відповідь jlliagre -name "*.[ch]"без пояснень згортає вираз імені . Це має переваги у тому, щоб спростити командний рядок і, зокрема, усунути  -o. Знайти вирази за участю -oважко правильно. Ваш помиляється; якщо ваша команда виправлена ​​таким чином, що вона не помиляється (як у відповіді Жилла), вона запускається grepлише у .hфайлах. Вам потрібно зробити '(' -name '*.c' -o -name '*.h' ')'.
G-Man каже: "Відновіть Моніку"

Відповіді:


18

Вам потрібно видалити єдині цитати, якими ви користуєтесь {}. Команду можна спростити так:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

Якщо ви використовуєте архаїчну версію пошуку GNU, це все одно має працювати:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;

На жаль, вони повинні були бути цитатами, а не заднім числом.
Девід Кеннеді

Котирування були б марними, оскільки {}не мають конкретного значення для оболонки.
jlliagre

З сторінок пошуку man: "Рядок" {} "замінюється поточним ім'ям файлу, який обробляється скрізь, де це відбувається в аргументах команди, а не тільки в аргументах, де він один, як у деяких версіях знаходження. Обидва ці конструкції, можливо, знадобиться уникнути (з позначкою '\') або цитувати їх, щоб захистити їх від розширення оболонкою. "
Девід Кеннеді

1
Я дійсно читав, що на сторінці керівництва, але факт, що я не знаю оболонки, що вимагає цитування фігурних дужок. Яку оболонку ви використовуєте?
jlliagre

баш З або без лапок я все одно отримую помилку.
Девід Кеннеді

10

"Аргумент відсутній -exec" зазвичай означає, що в аргументі - execвідсутній його термінатор. Термінатор повинен бути або аргументом, що містить лише символ ;(який потрібно котирувати в командній оболонці, тому це, як правило, записано \;або ';'), або два послідовні аргументи, що містять {}і +.

Стефан Шазелас визначив, що ви використовуєте старішу версію пошуку GNU, яка не підтримує -exec … {} +лише те -exec {} \;. Хоча GNU був пізнім користувачем -exec … {} +, я рекомендую вам придбати менш антикварний набір інструментів (наприклад, Cygwin , який включає в себе git і багато іншого, або GNUwin32 , якому не вистачає git, але у нього немає поганих спроб співробітників -to-use-linux-but-we-налагає-вібрує вібру, яку дає Cygwin). Ця функція була додана у версії 4.2.12 понад 9 років тому (це була остання ідентифікована функція, яка зробила findсумісну з GNU POSIX).

Якщо ви хочете дотримуватися старої GNU знахідки, ви можете використовувати -print0з , xargs -0щоб отримати аналогічну функціональність: згруповане виконання команд, що підтримує довільні імена файлів.

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

Завжди цитуйте підстановку в findкомандному рядку. В іншому випадку, якщо вам трапиться запустити цю команду з каталогу, що містить .cфайли, без котирувань *.cбуде розширено список списку .cфайлів у поточному каталозі.

Додавання /dev/nullдо grepкомандного рядка - трюк, щоб гарантувати, що grep завжди надрукує ім'я файлу, навіть якщо findтрапиться знайти одне збіг. З GNU find, інший метод полягає у передачі параметра -H.


1
Що ви маєте на увазі під керуванням поганого працівника, який намагається використовувати-linux-але-ми-нав’язувати вікна, що дає cygwin?
Девід Кеннеді

GNUwin32 не очікував :(
Девід Кеннеді

Дивіться мої коментарі до цього питання.
G-Man каже: "Відновіть Моніку"

Цитати навколо напівфабрикату працювали в рамках сценарію package.json.
bvj

2

Якщо така команда, як

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

повертає помилку

find: missing argument to -exec

ймовірною причиною є занадто стара GNU, findяка не підтримує синтаксис -exec mycommand {} +. У такому випадку заміна низької продуктивності - -exec mycommand {} \;це запуск mycommandодного разу для кожної знайденої цілі, а не збирання декількох цілей та виконання mycommandлише одного разу.

Однак GNU findне підтримує напр

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

оскільки GNU findпідтримує лише буквальне поєднання {} +замість більш загального {} additional parameters +. Зауважте, що між дужками та +символом не може бути нічого . Якщо ви спробуєте це, ви отримаєте ту ж помилку:

find: missing argument to -exec

Вирішення проблеми полягає у використанні синтаксису, {} additional parameters \;який працює, але виконує команду один раз для кожної знайденої цілі. Якщо вам потрібна більша продуктивність з GNU, findвам слід написати скрипт для обгортки, який може додавати додаткові параметри до наведених аргументів. Щось на зразок

#!/bin/bash
exec mycommand "$@" additional parameters

має бути досить хорошим. Або, якщо ви не хочете створювати тимчасовий файл, ви можете скористатись одним вкладишем для зміни порядку таких параметрів:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

який виконає mycommand {list of ttf files} extra arguments. Зауважте, що вам може знадобитися подвоїти спеціальні символи для удару після -cпрапора.


(1) Частина вищезазначеного, яка фактично відповідає на питання, вже була надана іншими людьми. (2) Те, що ви описуєте, - це не вада чи недолік у GNU find, а правильна поведінка, визначена POSIX .
G-Man каже: "Відновіть Моніку"

1
+1 Нарешті, хтось відповідає, чому додаткові параметри не працюють! Це здається недоліком у визначенні POSIX.
Джонатан

Якщо у вас GNU, findви, ймовірно, отримали GNU cp. У цьому випадку ви можете find ... -exec cp --target-directory ~/.fonts {} +зберегти {}в кінці рядка виконання.
roaima

1

find . -type f -perm 0777 -exec chmod 644 {}\;

помилка find: missing argument to ``-exec'.

Додавання пробілу між ними {}та \виправлення:

find . -type f -perm 0777 -print -exec chmod 644 {} \;


1
Такого питання в findкоманді немає в розглянутому питанні.
Kusalananda

У питанні це не добре, що я зрозумів, але проблема така ж "знайти: відсутній аргумент до` `-exec '", Проблема може виникнути з різних 2 причин, я відповів, тому що бачив те саме твердження проблеми.
ShreePool

@Kusalananda доброго горя, noob забезпечив рішення повідомленої помилки, яку заявляє ОП як у назві, так і в тілі питання.
bvj

@bvj Питання чітко стосується +форми -execваріанту для find. Ця відповідь виправляє проблему, якої у користувача, який задає питання, немає.
Kusalananda

-1

Я мав свою частку головних болів із синтаксисом exec у минулому. Більшість днів я віддаю перевагу приємнішому синтаксису баш:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

Він має деякі обмеження, коли ви хочете ставитися до файлів як до групи, оскільки кожен оцінюється послідовно, але ви можете передати вихідні дані в інше місце просто чудово


1
Хоча ця робота має тенденцію до роботи, вона значно менш корисна, ніж версія для чистого пошуку, оскільки вона не може правильно обробляти файли з пробілом у назві.
Ітан Рейснер

5
Ні, не робіть цього. Це порушується, як тільки файли містять пробіли та інші "дивні" символи. Це також складніше і повільніше find … -exec … \;, тому немає ніяких причин використовувати це, навіть якщо ви знаєте, що назви ваших файлів приручені.
Жил "ТАК - перестань бути злим"

це було корисно для моєї ситуації, коли мені потрібно було запустити кілька рядків логіки на основі імен файлів (наприклад, видалення символів, створення каталогів та переміщення файлів). Намагання знайти пошук кількох речей в одному execбуло занадто сильним головним болем за 5 хвилин, які я хотів витратити на це. Імена моїх файлів були приручені, і це вирішило мою проблему :)
gMale
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.