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