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

206

Мне помогли сегодня с командой, но она, кажется, не работает. Это команда:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {}\;

Оболочка возвращается

find: missing argument to `-exec'

В основном я пытаюсь рекурсивно просмотреть каталог (если у него есть другие каталоги) и выполнить команду ffmpeg .rmдля типов файлов и преобразовать их в .mp3типы файлов. Как только это будет сделано, удалите .rmфайл, который был только что преобразован.

Я ценю любую помощь в этом.

Abs
источник

Ответы:

340

-execКоманда должна быть прекращена с ;(так обычно нужно ввести \;или , ';'чтобы избежать interpretion оболочки) или +. Разница в том, что с ;, команда вызывается один раз для файла, с +, она вызывается как можно меньше раз (обычно один раз, но максимальная длина для командной строки, поэтому она может быть разделена) со всеми именами файлов , Смотрите этот пример:

$ cat /tmp/echoargs
#!/bin/sh
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

Ваша команда имеет две ошибки:

Во-первых, вы используете {};, но ;должен быть свой собственный параметр.

Во-вторых, команда заканчивается на &&. Вы указали «запустить поиск, и, если это было успешно, удалите файл с именем {};.». Если вы хотите использовать оболочку в -execкоманде, вам нужно явно запустить ее в оболочке, например -exec sh -c 'ffmpeg ... && rm'.

Однако вы не должны добавлять {} в команду bash, это вызовет проблемы при наличии специальных символов. Вместо этого вы можете передать дополнительные параметры в оболочку после -c command_string(см. man sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
damn.
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

Вы видите, что $вещь оценивается оболочкой в ​​первом примере. Представь, что есть файл с именем $(rm -rf /):-)

(Примечание: -не требуется, но первой переменной после команды назначается переменная $0, которая представляет собой специальную переменную, обычно содержащую имя запускаемой программы и устанавливающую это значение для параметра, немного нечисто, хотя и выиграла Наверное, здесь нет никакого вреда, поэтому мы установим это просто -и начнем с $1.)

Так что ваша команда может быть что-то вроде

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

Но есть и лучший способ. найти поддержку andи or, таким образом, вы можете делать такие вещи, как find -name foo -or -name bar. Но это также работает с -exec, который оценивается как истина, если команда успешно завершается, и ложь, если нет. Смотрите этот пример:

$ ls
false  true
$ find * -exec {} \; -and -print
true

Он запускает печать только в том случае, если команда была успешно выполнена, trueно не для false.

Таким образом, вы можете использовать два оператора exec, соединенные цепочкой -and, и последний будет выполнять только последний, если первый был успешно выполнен.

Мэриан
источник
3
Кажется, что ключом является строка Мариана «сам по себе - аргумент», именно это и было сделано для меня, с точки зрения лампочки и для моего примера кода. Спасибо.
Пьяммер
3
Это лучшее описание, которое я прочитал на -exec. Это очень мощный инструмент, но мне всегда трудно найти правильный синтаксис для него. Это сделало несколько вещей намного понятнее. Особо оборачиваем команду в отдельную оболочку. Ницца. Спасибо.
Eurospoofer
3
Обратите внимание, что -andи -orне являются портативными. POSIX определяет -aи-o , и фактически -aвсегда предполагается (следовательно, не требуется).
gniourf_gniourf
Также должен быть пробел перед терминатором. Ex "\;"не работает, но " \;"работает
frmdstryr
56

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

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;
Abs
источник
Не уверен, что получит переменную файла для удаления? Кто-нибудь знает, так ли это?
Abs
7
Чтобы проверить такие вещи, просто добавьте echoперед командами и посмотрите, что он делает.
Мариан
2
@Marian echoдовольно ненадежен - вы не можете определить разницу между echo "one argument"и echo one argument(выходные данные последнего являются ложными, поскольку на самом деле они передают echoдва совершенно разных аргумента). Гораздо лучше сделать что-то вроде этого -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n', который будет печатать вывод таким образом, чтобы сделать непечатаемые символы видимыми, чтобы вы могли обнаружить новые строки DOS и другие странности.
Чарльз Даффи
52

Попробуйте поставить пробел перед каждым \;

Работает:

find . -name "*.log" -exec echo {} \;

Не работает:

find . -name "*.log" -exec echo {}\;
Дастин Коулз
источник
1
Это сбивает меня с толку довольно часто. На днях я добавлю пробел по умолчанию.
Harperville
Для меня это работает как раз наоборот в Cygwin под Windows 7: до этого места нет \; работает, с пространством - нет. Но если я удаляю \, с пробелом раньше; это работает, и без места раньше; это не так, как описано здесь.
WebComer
7

Просто для вашей информации:
я только что попытался использовать команду "find -exec" в системе Cygwin (UNIX эмулируется в Windows), и там кажется, что обратная косая черта перед точкой с запятой должна быть удалена:
find ./ -name "blabla" -exec wc -l {} ;

Dominique
источник
Я действительно запутался. find /etc/nginx -name '*.conf' -exec echo {} ;и find /etc/nginx -name '*.conf' -exec echo {}\;дал тот же результат. :(
Кирби
Я использую оболочку Bash, которая поставляется с Git для Windows, и ответ Дастина Коулза мне подходит. Другими словами: без кавычек, обратная косая черта после точки с запятой, пробел после {}.
mamacdon
Там нет никакой разницы в значении, но в некоторых случаях вам нужно поставить обратную косую черту, в некоторых вы не можете поставить его, а в других случаях вы можете выбрать.
Доминик
2

На всякий случай, если кто-нибудь увидит подобные «отсутствующие аргументы -exec» в сценариях bash Amazon Opsworks Chef, мне нужно добавить еще одну обратную косую черту, чтобы избежать \;

bash 'remove_wars' do
  user 'ubuntu'
  cwd '/'
  code <<-EOH
    find /home/ubuntu/wars -type f -name "*.war" -exec rm {} \\;
  EOH
  ignore_failure true
end
Джон Купер
источник
2

Также, если у кого-то есть «find: отсутствующий аргумент для -exec», это может помочь:

В некоторых оболочках вам не нужно выполнять экранирование, т. Е. Вам не нужно "\" перед ";".

find <file path> -name "myFile.*" -exec rm - f {} ;
sellmaurer
источник
2
;Не цитируют или спасшийся здесь означает , что он может потребляться оболочки, а не читать find. Также -fи - fэто две разные вещи.
Чарльз Даффи
1

Тебе нужно сбежать, я думаю.

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} \-sameq {}.mp3 \&\& rm {}\;
Мэтью Смит
источник
0

И {}, и && вызовут проблемы из-за того, что будут расширены командной строкой. Я бы предложил попробовать:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;
VeeArr
источник
Если первая команда в exec завершится успешно, а вторая команда в exec будет выполнена, будет ли у нее доступ к {}переменной для удаления нужного файла?
Абс
На что ты {}расширяешься? Если он не содержит двух точек или запятых, которые останутся такими, как есть.
Мариан
0

Вы должны поставить пробел между {}и\;

Таким образом, команда будет выглядеть так:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;
Азафо Косса
источник
-4

Если вы все еще получаете «find: отсутствующий аргумент для -exec», попробуйте заключить аргумент execute в кавычки.

find <file path> -type f -exec "chmod 664 {} \;"
свататься
источник