найти: отсутствует аргумент для -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 find только добавила его (относительно) недавно (2005). Что find --versionтебе сказать?
Стефан Шазелас
2
@ Koveras, это было бы тогда. -exec {} +был добавлен в 4.2.12 в 2005 году. В более ранних версиях GNU вы можете использовать (не POSIX), -print0 | xargs -r0чтобы получить нечто подобное. 4.1с 1994 года.
Стефан Шазелас
1
JRFerguson указал (в ответе , который был удален) , что -nameаргументы модели должны быть указаны: -name "*.c" -o -name "*.h". Это правда, хотя это не связано с -execошибкой. Вы заметите, что все остальные ответы помещают символы подстановки в кавычки, хотя об этом упоминает только Жиль. … (Продолжение)
G-Man говорит: «Восстановите Монику»
1
(Продолжение)… Ответ Джлиагре сворачивает выражение имени -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
источник
Ой, они должны были быть кавычками, а не кавычками.
Дэвид Кеннеди
Кавычки были бы бесполезны, так как {}не имеют конкретного значения для оболочки.
Jlliagre
Из страниц справки по поиску: «Строка '{}' заменяется текущим именем файла, которое обрабатывается везде, где оно встречается в аргументах команды, а не только в аргументах, где она одна, как в некоторых версиях find. Оба эти конструкции, возможно, должны быть экранированы (с '\') или заключены в кавычки, чтобы защитить их от расширения оболочкой. "
Дэвид Кеннеди
1
Я действительно читал об этом на странице руководства, но дело в том, что нет никакой оболочки, о которой я знаю, которая требует цитирования фигурных скобок. Какую оболочку вы используете?
Jlliagre
Баш. С или без кавычек я получаю ошибку в любом случае.
Дэвид Кеннеди
10

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

Stephane Chazelas определил, что вы используете более старую версию GNU find, которая не поддерживает -exec … {} +только -exec {} \;. Хотя GNU был поздним последователем -exec … {} +, я рекомендую вам приобрести менее антикварный набор инструментов (например, Cygwin , который включает в себя git и многое другое, или GNUwin32 , в котором отсутствует git, но нет попытки плохого сотрудника). -все-использую-linux-но-мы-навязываем окна, которые дает 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
Что вы имеете в виду под «плохой служащий, пытающийся использовать линукс, но мы навязываем окна», который дает 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. Обратите внимание, что вам может потребоваться двойная экранирование специальных символов для bash после -cфлага.

Микко Ранталайнен
источник
(1) Часть вышеупомянутого, которая фактически отвечает на вопрос, уже была дана другими людьми. (2) То, что вы описываете, является не недостатком или недостатком GNU find, а правильным поведением, указанным в POSIX .
G-Man говорит: «Восстановите Монику»
1
+1 Наконец, тот, кто отвечает, почему не работают дополнительные параметры! Это кажется недостатком в определении POSIX.
Джонатан
Если у вас есть GNU, findу вас, вероятно, есть GNU cp. В этом случае вы можете find ... -exec cp --target-directory ~/.fonts {} +оставить {}в конце строки выполнения.
Ройма
1

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

получил ошибку find: missing argument to ``-exec'.

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

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

ShreePool
источник
1
Нет такой проблемы в findкоманде в рассматриваемом вопросе.
Кусалананда
В Вопросе это не так, хорошо, что я понял, но проблема та же: «найти: отсутствующий аргумент для` -exec '», проблема может возникнуть по другой причине-2, я ответил, потому что я видел ту же формулировку проблемы.
ShreePool
@ Kusalananda, черт возьми, нуб предоставил решение для сообщенной ошибки, которая указана ФП в заголовке и основной части вопроса.
bvj
@bvj Вопрос явно касается +формы -execопции find. Этот ответ исправляет проблему, которой нет у пользователя, задающего вопрос.
Кусалананда
-1

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

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

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

tolster710
источник
1
Хотя это имеет тенденцию работать, это значительно менее полезно, чем версия чистого поиска, потому что она не может правильно обрабатывать файлы с пробелами в имени.
Этан Рейснер,
5
Нет, не делай этого. Это нарушается, как только файлы содержат пробелы и другие «странные» символы. Это также сложнее и медленнее, чем find … -exec … \;, поэтому нет причин использовать это, даже если вы знаете, что ваши имена файлов ручные.
Жиль "ТАК - перестань быть злым"
это было полезно для моей ситуации, когда мне нужно было запустить несколько строк логики на основе имен файлов (таких как удаление символов, создание каталогов, а затем перемещение файлов). Попытка найти, чтобы сделать несколько вещей в одном, execбыла слишком большой головной болью для 5 минут, которые я хотел потратить на это. Мои имена файлов были ручными, и это решило мою проблему :)
gMale