Shell find и запуск команды, удаление расширения, манипуляция с {}

Нужно вытянуть из mp4 в mp3 звуковую дорожку. В общем работает такое

find . -name "*.mp4" -exec ffmpeg -i {} -b:a 192K -vn {}.mp4 \;

Но хотелось бы очистить (удалить) расширение mp4 а то на выходе, конечно получаю .mp4.mp3

Делал разными способами

find . -name "*.mp4" -exec echo {}#.mp4 \;
find . -name "*.mp4" -exec echo {{}#.mp4} \;
find . -name "*.mp4" -exec echo ${{}#.mp4} \;

Для теста, конечно, заменил команду, чтобы увидеть как будет очищаться расширение, но не получилось. Где моя ошибка?


Ответы (1 шт):

Автор решения: aleksandr barakin

например, так:

$ find -name \*.mp4 -exec sh -c 'echo "вход: $1 выход: ${1%.mp4}.mp3"' -- '{}' \;
вход: ./файл.mp4 выход: ./файл.mp3

обратите внимание, что вторым аргументом программе sh передаётся строка в одинарных кавычках. это чтобы экземпляр оболочки, в котором вы запускаете команду, не пытался обрабатывать встречающиеся в строке $1 и ${1%.mp4}. если надо заключить всё-таки в двойные кавычки, то символ $ надо будет «заэскейпить»: \$.


Где моя ошибка?

find . -name "*.mp4" -exec echo ${{}#.mp4} \;

ход мысли, в общем, правильный — воспользоваться parameter expansion. но:

  1. программа find этого не умеет, а умеет программа, выполняющая функцию (posix-совместимой) оболочки, которую (программу) и надо явно вызвать (как в моём примере)
  2. как явствует из самого названия («parameter expansion»), в конструкции должен присутствовать параметр (в терминологии стандарта posix — это имя переменной, номер аргумента или спецсимвол).

    • так: ${xyz%строка} — можно (обрабатываться будет значение переменной xyz)
    • и так: ${1%строка} — можно (обрабатываться будет первый аргумент)
    • а так: ${./файл.mp4%строка} — нельзя (надеюсь, понятно, откуда появляется строка ./файл.mp4 — её подставит программа find вместо {}
  3. ну и по мелочи: ${параметр#строка} — удалит префикс, а вам надо суффикс: ${параметр%строка}
→ Ссылка