尝试在大型音乐收藏中进行从 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
可以解决这个问题吗?
答案1
这就是你绝不使用for
循环来迭代输出可能包含空格的命令。特别是如果该输出是可能包含以下内容的文件名列表任何事物除了/
和\0
。你已经陷入bash 陷阱 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
可确保 bash 在将其传递给 之前不会对其进行扩展find
。这对于当前目录中有与该 glob 匹配的文件的情况非常重要。您
-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
find 更好地发挥作用-print0
。"${file%.mp3}.ogg";
:这只是删除.m4a
后缀并将其替换为,.ogg
这样您就得到了foo.ogg
而不是foo.m4a.ogg
。
其余部分与您尝试过的相同,所以我想您理解它。
答案2
使用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
。
答案3
这可能是你想要的解决方案
#!/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