这回答使用 for 循环将一批 mp4 转换为 mp3。
我想用一行代码实现类似的功能。经过反复尝试,我找到了以下代码。
ls | grep .mkv | xargs -I {} ffmpeg -i {} -codec copy {}.mp4
但是,输出文件名现在是video.mkv.mp4
。
我知道我可以简单地再写一行来更改扩展名
ls | grep .mkv.mp4 | sed -e "p;s/\.mkv.mp4$/\.mp4/" | xargs -n2 mv
我想知道是否有一个单一的解决方案。
答案1
没有理由(除了可读性之外)你不能将 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
如果你决定使用xargs
,那么一个选择是切换到 Z-shell,在那里你可以使用glob 限定符生成r每个匹配文件名的 oot,然后根据需要添加输入和输出扩展名。例如:
print -rNC1 ./*.mkv(.N:r) | xargs -r0 -I{} ffmpeg -i {}.mkv -codec copy {}.mp4 # NB zsh not bash
print
请注意,我将and -切换为空分隔符,xargs
这样您就可以处理任何合法的文件名,包括包含换行符的文件名。
另一个选项是从 切换xargs
到GNU parallel
,它有用于替换字符串的附加选项,包括{.}
替换不带扩展名的文件名(相当于循环版本${f%.mkv}
或 Z-shell 的:r
修饰符):
printf '%s\0' ./*.mkv | parallel -q0 ffmpeg -i {} -codec copy '{.}.mp4' # any shell, including bash