我有几部不同系列的广播剧。有些已经是单轨的,有些是多轨的。我希望一切都是单轨的。我不介意重新编码;事实上,我想将它们传输到我的移动设备上,并且更喜欢 opus 输出。
从单个有声读物的文件夹中,这似乎可以解决问题,将 mp3 转换为 opus:
ffmpeg -i "concat:$(ls *.mp3 | tr '\n' '|')" -acodec opus test.opus
现在,我确实有很多想要转换的多轨广播节目。我想定义一个函数,我可以使用它find
或将结果通过管道传递到ls
其中。
我摸索着这个的变体:
function audioconcat { folder=$1; iformat=$2; oformat=$3; echo $folder; echo $iformat; echo $oformat; ffmpeg -i \'concat:$(find "$folder" -name *.$iformat | tr '\n' '|' | tr ' ' '\ ' | head -c -1)\' -acodec $oformat \'$folder.$oformat\'; }
因此,我们的想法是在文件夹内查找给定输入格式的文件,将它们放入 ffmpeg 连接中,将流编码为给定的输出格式,并使用文件夹名称将其保存为单个文件。
但是,我似乎总是遇到空格和/或嵌套函数调用的问题。
我可以做什么来修复我的功能?或者,有什么更好的方法来进行上述转换?
答案1
您已经在代码中演示了多种可以改进的反模式。看为什么你不应该解析 ls(1) 的输出。您不需要解析ls
命令的输出,并避免将多个 shell 管道与tr
command 和一起使用find
。
建议更好地使用本机 shell 提供的 glob 选项,在您的情况下应该是 shell bash
。
这段代码可以很好地使用它为文件通配提供的选项来$(ls *.mp3 | tr '\n' '|')
编写,如下所示bash
shopt -s nullglob
mp3FileList=(*.mp3)
启用此扩展 shell 选项是为了确保在填充到数组时跳过空 glob 结果而不是对其进行处理。您应该cd
进入该文件夹并执行以下操作。请注意|
数组后面的最后一个,因为您最初也将其包含在列表中。如果不需要,请将其删除。
fileString=$( IFS='|'; echo "${mp3FileList[*]}|" )
|
现在,上面的变量将包含单独格式的文件列表,|
最后可以将其传递给您的ffmpeg
命令:
ffmpeg -i "concat:${fileString}" -acodec opus test.opus
关于将多个选项传递给脚本的第二个要求。你可以扩展这个脚本来做
audioConcat() {
(( "$#" < 3 )) && { printf 'insufficient arguments supplied' >&2; exit 1 ; }
cd "$1" || { printf 'unable to navigate to target\n' >&2; exit 2 ; }
shopt -q nullglob; nullglob_set=$?
((nullglob_set)) && shopt -s nullglob
local fileList
local fileString
fileList=(*."${2}")
if (( ${#fileList[@]} )); then
fileString=$( IFS='|'; echo "${fileList[*]}" )
ffmpeg -i "concat:${fileString}" -acodec "$3" "$1.$3"
else
printf 'unable to find files of extension %s\n' "$2" >&2
exit 3
fi
((nullglob_set)) && shopt -u nullglob
}
请记住,在调用函数时,将参数传递为
audioConcat '/path/to/mp3files/' 'mp3' 'opus'
强烈建议您注释掉ffmpeg
上面函数中的行并查看变量是否已创建作为在调用实际命令之前需要。另请确认|
文件列表中是否需要尾随。
函数中使用的结构的快速总结
- 路径名扩展期间设置的选项
nullglob
将避免扩展空的 glob,即,当未.mp3
找到文件时,扩展时数组将为空,而不是未扩展的 glob $(IFS='|'; echo "${mp3FileList[*]})
是一个巧妙的技巧,用于以单独的格式打印输出|
。我们正在子 shell(输入字段分隔符)中修改,IFS
因此它不会被全局修改。数组扩展[*]
会将字符串与IFS
设置的值连接起来。
一些杂项。需要考虑的注意事项:- 使用exit
在函数中使用 from 实际上会出口您正在运行该函数的当前 shell。从命令行使用时可能不建议使用它,而从具有适当解释器 she-bang 设置的脚本运行时更适合,在这种情况下,它将从启动的子 shell 中退出以运行脚本。如果您计划更频繁地从命令行使用,请将exit
调用替换为return
.