Rav*_*euk 4 command-line video ffmpeg batch-rename
这个答案使用 for 循环将一批 mp4 转换为 mp3。
我想只用一行代码实现类似的目标。经过一番尝试和错误,我想出了以下代码。
ls | grep .mkv | xargs -I {} ffmpeg -i {} -codec copy {}.mp4
Run Code Online (Sandbox Code Playgroud)
但是,输出文件名现在是video.mkv.mp4.
我知道我可以简单地再写一行来更改扩展名
ls | grep .mkv.mp4 | sed -e "p;s/\.mkv.mp4$/\.mp4/" | xargs -n2 mv
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一种单线解决方案。
没有理由(除了可读性之外)您不能将 shell 循环放在一行代码中 - 无论您使用 shell 循环还是xargs -I{}最终都会对ffmpeg每个文件调用一次。
无论如何,我会避免ls | grep- 相反,使用 shell glob。因此,作为一句话(在任何类似 POSIX 的 shell 中,例如 bash):
for f in ./*.mkv; do ffmpeg -i "$f" -codec copy "${f%.mkv}.mp4"; done
Run Code Online (Sandbox Code Playgroud)
如果您决定使用xargs,那么一种选择是切换到 Z-shell,您可以在其中使用glob 限定符生成每个匹配文件名的根,然后根据需要添加输入和输出扩展名。例如:
print -rNC1 ./*.mkv(.N:r) | xargs -r0 -I{} ffmpeg -i {}.mkv -codec copy {}.mp4 # NB zsh not bash
Run Code Online (Sandbox Code Playgroud)
print请注意,我将and -切换为空分隔符xargs,这允许您处理任何合法文件名,包括包含换行符的文件名。
另一种选择是从xargsto切换GNU parallel,它具有用于替换字符串的附加选项,包括{.}替换不带扩展名的文件名(相当于循环版本${f%.mkv}或 Z-shell 的:r修饰符):
printf '%s\0' ./*.mkv | parallel -q0 ffmpeg -i {} -codec copy '{.}.mp4' # any shell, including bash
Run Code Online (Sandbox Code Playgroud)