Пытаясь выполнить массовое преобразование из 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
это исправит?
Это - одна из причин, почему Вы никогда не используете 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
.
Остальное совпадает с Вами, попытался так, я предполагаю, что Вы понимаете это.
Используйте 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
.
Это может быть решением того, что Вы хотите
#!/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