знайти: відсутній аргумент до -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файл, щойно перетворений.

Я вдячний за будь-яку допомогу з цього приводу.

Відповіді:


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 /):-)

(Бічна примітка: The -не потрібна, але перша змінна після команди присвоюється змінній $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
Ключовим, здається, є рядок Маріана: "the; a arg's on own". Саме це зробило для мене, лампочка і для мого зразка коду. Дякую.
племмер

3
Ось про найкращий опис, який я читав на -exec. Це надзвичайно потужно, але мені завжди важко знайти правильний синтаксис для цього. Це зробило кілька речей набагато зрозумілішими. Особливо загортаючи команду в окрему оболонку. Приємно. Дякую.
Євроспофер

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 {} \;

Не знаєте, чи отримає змінну файлу видалення? Хтось знає, чи так це?
Абс

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 {} ;


Я справді розгубився. find /etc/nginx -name '*.conf' -exec echo {} ;і find /etc/nginx -name '*.conf' -exec echo {}\;дав такий же результат. :(
Кірбі

Я запускаю оболонку Bash, яка постачається з Git для Windows, і відповідь Дастіна Каулса працює на мене. Іншими словами: жодних лапок, зворотна косої риски не пропускається крапкою з комою, пробіл після {}.
mamacdon

Немає різниці в значенні, але в деяких випадках вам потрібно поставити звороту косу рису, в деяких випадках ви не можете її поставити, а в інших випадках ви можете вибрати.
Домінік

2

На всякий випадок, якщо хтось побачить подібні "аргументи про відсутніх -exec" у скриптах базування 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: missing для -exec", це може допомогти:

У деяких снарядах вам не потрібно робити втечу, тобто вам не потрібно "\" перед ";".

find <file path> -name "myFile.*" -exec rm - f {} ;

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 \{} \;

Якщо перша команда в exec буде успішною, а друга команда в exec виконана, чи буде вона все ще мати доступ до {}змінної, щоб видалити потрібний файл?
Абс

До чого ти {}розширюєш тинік ? Якщо вона не містить двох крапок або коми, які залишаться такими, як є.
Маріан

0

Ви повинні поставити пробіл між {}і\;

Отже команда буде такою:

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

-4

Якщо ви все ще отримуєте "find: missing argument to -exec", спробуйте обернути аргумент Execute в лапки.

find <file path> -type f -exec "chmod 664 {} \;"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.