Как работает команда поиска с использованием команды «find… -exec sh -c '…' sh {} +»?

8

@StephaneChazelas опубликовал следующее решение этого вопроса: возникли проблемы с использованием «find -exec {} +» .

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

Что именно здесь происходит? Что конкретно делает последний sh {}? Кажется, что это просто для того, чтобы успокоить -execкоманду find, чтобы она могла что-то сделать, NOOP.

Я мог бы так же легко положить echo {}туда, и, кажется, работает просто отлично.

SLM
источник

Ответы:

9

Синтаксис:

find ... -exec cmd {} +

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

При необходимости он может разбить список файлов и вызвать cmdнесколько раз. Например, это может в конечном итоге вызвать:

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321

Ограничение в том, что {}это должно быть последним. Вы не можете, например, написать:

find ... -exec cmd {} other args +

как вы могли бы ';'вместо '+'.

Ты можешь написать:

find ... -exec echo foo {} +

но нет:

find ... -exec echo {} foo +

Итак, если вам нужно добавить несколько дополнительных аргументов cmdпосле списка файлов, вам придется прибегнуть к вызову оболочки. (Другими причинами, по которым вам нужно вызывать оболочку, может быть любое время, когда вам нужно использовать такую ​​функцию оболочки, как перенаправления, каналы, некоторые расширения строк ....)

В sh -c 'inline-script' x a b c, поскольку inline-script, $0есть x, $1есть a, $2есть b... так же, "$@"как и список этих трех аргументов: a, b и c. Итак, в:

find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +

Для встроенного скрипта , $0(который используется, например , при отображении сообщений об ошибках) установлен в find-shи "$@"список файлов (что findрасширяет {}к).

Используя execспециальную встроенную оболочку:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +

Мы говорим оболочке не форкать дополнительный процесс для запуска cmd, а вместо этого запускать его в том же процессе (заменяя запущенный процесс оболочки этой командой). Некоторые оболочки любят bash, zshа некоторые реализации kshделают это неявно для последней команды в скрипте.

Стефан Шазелас
источник
Не могли бы вы использовать подоболочку вместо exec там? -exec sh -c '(cmd1; cmd2;)' find-sh {} +?
SLM
Так что, если я вас правильно понимаю, find-sh {}это аргументы команды sh -c '...', верно?
SLM
@slm, findбудем называть /bin/shс аргументами ("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside ... , that maps (the shells maps that) to $ 0` существо "find-sh", и позиционные параметры ( $1, $2... , которые вы могли бы сказать , аргументы к инлайн сценария ) являются ./file1, ./file2.
Стефан Шазелас