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

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

Я пытаюсь выполнить следующую команду:

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 '{}' \+

решение1

В ваших попытках возникло несколько проблем, включая обратные кавычки, используемые вместо кавычек (удаленные при последующих редактировании вопроса), пропущенные кавычки там, где они необходимы, дополнительные кавычки там, где они бесполезны, пропущенные скобки для группировки -oпредложений и различные реализации findused (подробности см. в комментариях и чате).

В любом случае, команду можно упростить следующим образом:

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

или, если вы используете архаичную версию GNU find, это всегда должно сработать:

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

решение2

«отсутствует аргумент to -exec» обычно означает, что аргумент to - execне имеет своего терминатора. Терминатор должен быть либо аргументом, содержащим только символ ;(который необходимо заключить в кавычки в команде оболочки, поэтому обычно он пишется \;или ';'), либо двумя последовательными аргументами, содержащими {}и +.

Стефан Шазелас определилчто вы используете старую версию GNU find, которая не поддерживает -exec … {} +, а только -exec {} \;. Хотя GNU поздно принял -exec … {} +, я рекомендую вам получить менее устаревший набор инструментов (например,Cygwin, который включает в себя git и многое другое, илиGNUwin32, в котором отсутствует git, но нет и атмосферы «плохой сотрудник пытается использовать Linux, но мы навязываем Windows», как в Cygwin. Эта функция была добавлена ​​в версии 4.2.12 более 9 лет назад (это была последняя идентифицированная функция, которая сделала GNU findPOSIX-совместимой).

Если вы предпочитаете использовать более старую версию GNU find, вы можете использовать -print0with 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.

решение3

Если команда, такая как

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. Обратите внимание, что вам может потребоваться дважды экранировать специальные символы для bash после -cфлага.

решение4

В прошлом у меня были проблемы с синтаксисом exec. Теперь я предпочитаю более удобный синтаксис bash:

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

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

Связанный контент