Для цикла с Unix найти

Пытаясь выполнить массовое преобразование из M4A в OGG в большой музыкальной коллекции, я имею:

#!/bin/sh
for i in `find /home/family/Music -name *.m4a -print0`
   #do ffmpeg -i "$i" -acodec libvorbis -aq 6 -vn -ac 2 "$i.ogg";
   do echo $i
done

Все файлы будут иметь пробелы в своих именах, вывод для вышеупомянутого показывает один файл вроде этого:

/home/family/Music/The
Kooks/Inside
In
_
Inside
Out/06
You
Don't
Love
Me.m4a

Каждый пробел обозначает новую строку, я думал -print0 это исправит?

6
задан 1 October 2014 в 21:11

3 ответа

Это - одна из причин, почему Вы никогда не используете a for цикл для итерации по команде, вывод которой может содержать пробелы. Особенно, если тот вывод является списком имен файлов, которые могут содержать что-либо кроме / и \0. Вы попали в ловушку удара номер 1. Всегда используйте while вместо этого. Для проверки это работает со всеми именами файлов, включая тех, которые имеют пробелы, новые строки, вкладки, обратные косые черты или любые другие странные символы, используют это:

find /home/family/Music -name '*.m4a' -print0 | while IFS= read -r -d '' file; do
     ffmpeg -i "$file" -acodec libvorbis -aq 6 -vn -ac 2 "${file%.m4a}.ogg";
done

Объяснение

  • Обратите внимание, что я заключил в кавычки *.mp4a который гарантирует, что удар не развернет его прежде, чем передать его find. Это важно для случаев, где у Вас есть файлы, которые соответствуют тому шарику в Вашем текущем каталоге.

  • -print0, поскольку Вы, вероятно, знаете, причины find разделить его результаты с \0 вместо новых строк.

  • IFS= : Это ни на что устанавливает символ поля ввода, гарантируя, что никакое разделение слова не произойдет.

  • while read -r -d '' file: Это выполнит итерации по результатам, сохраняя каждого как $file, точно так же, как for file in $(command). Опции (от help read):

     -r     do not allow backslashes to escape any characters
     -d delim   continue until the first character of DELIM is read, rather
        than newline
    

    Установка разделителя к пустой строке (-d '') делает read играйте по правилам с находкой -print0.

  • "${file%.mp3}.ogg"; : Это должно просто удалить .m4a суффикс и замена это с .ogg таким образом, Вы добираетесь foo.ogg вместо foo.m4a.ogg.

Остальное совпадает с Вами, попытался так, я предполагаю, что Вы понимаете это.

15
ответ дан 1 October 2014 в 21:11

Используйте xargs с -0 опция или используйте find собственный exec опция:

find /home/family/Music -name '*.m4a' -exec ffmpeg -i "{}" -acodec libvorbis -aq 6 -vn -ac 2 "{}.ogg" \;
# or:
find /home/family/Music -name '*.m4a' -print0 | xargs -0 -i ffmpeg -i {} -acodec libvorbis -aq 6 -vn -ac 2 {}.ogg

Примечание, что в обоих случаях (и в Вашей исходной команде), x.m4a будет преобразован в x.m4a.ogg.

0
ответ дан 1 October 2014 в 21:11

Это может быть решением того, что Вы хотите

#!/bin/bash    
find  /home/family/Music -type f -name '*.m4a' -print0 | while IFS= read -r -d '' i; 
  do
   #do ffmpeg -i "$i" -acodec libvorbis -aq 6 -vn -ac 2 "$i.ogg"; 
   echo $i
done
0
ответ дан 1 October 2014 в 21:11

Другие вопросы по тегам:

Похожие вопросы: