Bash、FFmpeg、文件名中的空格问题

3
我有一个关于ffmpeg和文件夹/文件名中空格的问题。我的代码如下所示:
cd /volume1/PUBLIC/Musik/AutoConvert
find . -type d -exec mkdir -p -- /volume1/PUBLIC/Musik/Converted/{} \;
find -type f |sed 's|./||' |while read NEWNAME; do
ffmpeg -i ""/volume1/PUBLIC/Musik/AutoConvert/"$NEWNAME""" -codec:a libmp3lame -qscale:a 2 "/volume1/PUBLIC/Musik/Converted/"${NEWNAME%.[Ff][Ll][Aa][Cc]}".mp3"
echo done with file: "$NEWNAME"
done

但是如果有空格,使用ffmpeg就会失败。我的文件夹结构如下:

user@NAS:/volume1/PUBLIC/Musik/AutoConvert$ find -type f |sed 's|./||'
A B/C.mp3
A B/C D.mp3
A/C D.mp3
A/C.mp3

/Converted/A/C.mp3 可以正常工作,但是其他包含空格的文件夹或文件名都无法正常工作。
[NULL @ 0x20bb3e0] Unable to find a suitable output format for '/volume1/PUBLIC/Musik/Converted/A/C'
/volume1/PUBLIC/Musik/Converted/A/C: Invalid argument
done with file: A/C D.mp3

[NULL @ 0x11bf280] Unable to find a suitable output format for '/volume1/PUBLIC/Musik/Converted/A'
/volume1/PUBLIC/Musik/Converted/A: Invalid argument
done with file: A B/C D.mp3

[NULL @ 0x11f93e0] Unable to find a suitable output format for '/volume1/PUBLIC/Musik/Converted/A'
/volume1/PUBLIC/Musik/Converted/A: Invalid argument
done with file: A B/C.mp3

如果我在FFmpeg命令中不使用双引号,会出现以下错误:

/volume1/PUBLIC/Musik/AutoConvert/A: Is a directory
done with file: A B/C.mp3

/volume1/PUBLIC/Musik/AutoConvert/A: Is a directory
done with file: A B/C D.mp3

/volume1/PUBLIC/Musik/AutoConvert/A/C: No such file or directory
done with file: A/C D.mp3

看起来我正在正确的道路上...只是离我的目标太远了。

有人能提供一些帮助吗?


1
为什么不直接使用"/volume1/PUBLIC/Musik/AutoConvert/$NEWNAME" .... "/volume1/PUBLIC/Musik/Converted/${NEWNAME%.[Ff][Ll][Aa][Cc]}.mp3"?带有空格的变量值应该用双引号括起来。祝你好运。 - shellter
1
为什么要去掉 ./ 前缀,而不是直接告诉 find 在第一次输出时就不要加上它们呢?例如:find . -type f -printf '%P\0' | while IFS= read -r -d '' 不会有任何 ./ 前缀(虽然这并不会对任何事情造成影响)。 - Charles Duffy
2
"" 完全没有任何作用:它启动了一个引用上下文并立即结束它,因此对周围代码的解析方式没有任何影响。 - Charles Duffy
1个回答

1
也许这段代码可以帮助你。
#!/bin/bash
cd /volume1/PUBLIC/Musik/AutoConvert 2>/dev/null || { echo "The folder is unavailable."; exit 1; }
find . -type d -exec mkdir -p -- /volume1/PUBLIC/Musik/Converted/{} \;
while IFS= read -r -d $'\0' NEWNAME; do
    ffmpeg -i "/volume1/PUBLIC/Musik/AutoConvert/$NEWNAME" -codec:a libmp3lame -qscale:a 2 "/volume1/PUBLIC/Musik/Converted/${NEWNAME%.*}.mp3"
    echo "done with file: $NEWNAME"
done < <(find . -iname '*.flac' -printf '%P\0')

可能应该在 find 命令中加上 -iname '*.flac',这样我们就不会将非 FLAC 文件视为输入(因此参数扩展删除扩展名失败)。 - Charles Duffy
我还建议(就像http://shellcheck.net/一样)在`cd`上加上`|| exit,这样如果/volume1/PUBLIC/Musik/AutoConvert`不可用,我们就不会继续在错误的目录中运行。 - Charles Duffy
1
据我所知,ffmpeg可以从标准输入读取数据,因此它可能会窃取部分文件名列表。我建议通过在read命令中添加<&3,并在done之后使用3<而不是仅使用<,将文件列表发送到FD 3。 - Gordon Davisson
似乎Synology修改了他们的bash4.3... sh:-c:第6行:附近意外标记符号<' sh:-c:第6行:done < <(find . -iname '*.flac' -printf '%P\0')' - Ha.Maier
1
@Ha.Maier 你必须使用 bash,而不是 sh。 - Darby_Crash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接