Почему это не работает для цикла?

Это на Ubuntu 12.04. Я пытаюсь выяснить, как получить ffmpeg для пакетного преобразования FLAC в MP3, рекурсивно. Если я cd в каталог и

 for f in *.flac; do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 "${f/%flac/mp3}"; done 

Это прекрасно работает. Однако, когда я пытаюсь это сделать, это не работает:

  • Как я могу рекурсивно скопировать файлы с расширением файла, сохраняя структуру каталогов?
  • Ubuntu grep, find и т. Д.: Вывод «Разрешение отказано» и «Нет такого файла или каталога»
  • Locate не находит все файлы, которые он должен
  • Найти файлы документов и скопировать их в другой каталог
  • Keep Find bar открыть все остальные вкладки в Firefox 25
  • Как я могу найти файлы, не соответствующие конкретному расширению в Windows XP?
  •  for f in "$(find . -type f -name *.flac)"; do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 "${f/%flac/mp3}"; done 

    Это даже не вызывает каких-либо полезных ошибок (но, в любом случае, это результат, не нужно жаловаться):

     evilsoup@enchantment:~/Music/Jean Sibelius$ for f in "$(find . -type f -name *.flac)"; do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 "${f/%flac/mp3}"; done ffmpeg version git-2012-12-18-b7e085a Copyright (c) 2000-2012 the FFmpeg developers built on Dec 18 2012 19:23:11 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5) configuration: --enable-gpl --enable-libfaac --enable-libfdk-aac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx --enable-x11grab --enable-libx264 --enable-nonfree --enable-version3 libavutil 52. 12.100 / 52. 12.100 libavcodec 54. 80.100 / 54. 80.100 libavformat 54. 49.102 / 54. 49.102 libavdevice 54. 3.102 / 54. 3.102 libavfilter 3. 28.100 / 3. 28.100 libswscale 2. 1.103 / 2. 1.103 libswresample 0. 17.102 / 0. 17.102 libpostproc 52. 2.100 / 52. 2.100 ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/02. Symphony No.1.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/03. Symphony No.1.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/stripped2.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/05. Symphony No.1.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/stripped3.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/09. Andante festivo.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/08. Symphony No.3.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/01. Finlandia.flac ./Symphonies 1, 2, 3 & 5 (Oslo Philharmonic Orchestra Conducted by Mariss Jansons) Disc 1/07. Symphony No.3.flac ./Symphonies 1, 2, 3 & 5 

    Я сам тестировал команду find , и она работает так, как ожидалось, поэтому проблема должна быть связана с взаимодействием между find и for .

    Я знаю, что могу что-то сделать с опцией find -exec , но я не могу найти способ сделать замену строк, как я могу, с помощью bash for loop, и я бы предпочел не иметь кучу file.flac.mp3 s для решения, даже если они могут быть исправлены с простым rename .

  • Как предотвратить Bash от изменения истории?
  • Ubuntu / Gnome: открыть приложение в определенной рабочей области
  • Как изменить оболочку в Ubuntu?
  • Как я могу рекурсивно скопировать файлы с расширением файла, сохраняя структуру каталогов?
  • Почему «source <(cmd)» работает, но не «$ (cmd)»
  • Как вы можете настроить подсказку терминала bash с помощью смайликов?
  • 3 Solutions collect form web for “Почему это не работает для цикла?”

    Двойные кавычки вокруг команды $(find ...) позволяют видеть результат поиска как одно имя файла, что явно не то, что вы хотите.

    Существует несколько способов добиться того, чего вы хотите:

    • Сделать find выполнить ffmpeg напрямую (без трубопроводов, без петель):

       find . -type f -name *.flac -exec bash -c ' ffmpeg -i "$0" -c:a libmp3lame -q:a 2 "${0/%flac/mp3}" ' {} \; 
    • Используйте find ... -print0 | xargs -0 ... find ... -print0 | xargs -0 ... вместо for, который специально предназначен для этих целей:

       find . -type f -name *.flac -print0 | xargs -0 -I {} bash -c ' ffmpeg -i "$0" -c:a libmp3lame -q:a 2 "${0/%flac/mp3}" ' {} 
    • Измените IFS только на новую строку, используйте ту же команду, что и раньше, минус двойные кавычки:

       IFS=$'\n' for f in $(find . -type f -name *.flac); do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 "${f/%flac/mp3}" done unset IFS 

      Команда unset IFS изменяет IFS на значение по умолчанию (не требуется внутри сценария оболочки, если только оно не вмешивается в последующие команды).

    Пожалуйста, прочтите BashFAQ / 020 – Вики Грега . Чтобы правильно перебрать вывод find , вот метод, который должен справляться со всеми видами странных символов в именах файлов (пробелы, символы новой строки, globbing и т. Д.),

     while IFS= read -r -d '' file; do ffmpeg -i "$f" -c:a libmp3lame -q:a 2 "${f/%flac/mp3}" done < <(find . -type f -name "*.flac" -print0) 

    Не забудьте указать "*.flac" чтобы предотвратить расширение, если есть файлы в текущем каталоге, заканчивающемся на .flac .

    Как и очень тонкие ответы, перечисленные здесь, я с тех пор обнаружил, что GNU Parallel может это сделать:

     find . -type f -name "*.flac" | parallel ffmpeg -i {} -c:a libmp3lame -q:a 2 {.}.mp3 

    {.} Удаляет расширение файла из имени файла. GNU Parallel по умолчанию использует новую строку как разделитель, поэтому нет необходимости использовать find ... -print0 | parallel -0 ... find ... -print0 | parallel -0 ... если вы не ожидаете имена файлов, содержащие новые строки.

    Как следует из названия, GNU Parallel запускает параллельные процессы – по одному заданию на ядро ​​процессора по умолчанию. Так что это может немного ускорить работу; Не так много в этом конкретном случае, поскольку ffmpeg многопоточен сам по себе … но все же.

    Давайте будем гением компьютера.