我写这个是为了帮助我对一些视频进行批量编码:
find -name '*.mkv' -exec HandBrakeCLI -Z "Android Tablet" \
-c "1-3" -m -O --x264-tune film -E copy --decomb -s 1 -i {} \
-o `echo {} | tr mkv m4v` \;
然而,它会灾难性地失败——它将每个 700-900MB 的文件替换为 36KB 的文件。
值得注意的是,HandBrake 能够读取和打印视频文件的属性;只有当它继续对其进行编码时,才会因为文件无效而失败。所以看来覆盖发生在它到达......
-o `echo {} | tr mkv m4v`
...但我不知道为什么会这样。我只是想将输出文件名从whatever.mkv 更改为whatever.m4v
文件名没有空格。12-the-revenge.mkv
例如,它们的形式为。
答案1
反引号表达式:(echo {} | tr mkv m4v
即不是出于各种原因,你想要什么;见下文)在解析 find 命令时展开一次。如果您使用bash
,它通常会扩展为{}
:
$ echo {} | tr mkv m4v
{}
事实上,这种情况发生在我机器上安装的每个 shell 上,除了fish,它输出一个空行。假设您没有使用fish
,那么实际看到的参数find
将是:
find -name '*.mkv' -exec HandBrakeCLI -Z "Android Tablet" \
-c "1-3" -m -O --x264-tune film -E copy --decomb -s 1 -i {} \
-o {} \;
简而言之,HandBrakeCLI
输入和输出都被给予相同的文件,我认为这就是您所看到的,尽管您对症状的描述不是很准确。
不幸的是,没有简单的方法可以让 find 来执行您希望它在操作中执行的扩展替换-exec
。您可以通过将命令传递给 来完成此操作bash -c
,但这将涉及命令行上额外的、令人困惑的引用。一个更清晰、更易读的解决方案是创建一个 shell 脚本文件,它可以迭代它的参数:
文件:(mkvtom4v.sh
请确保chmod a+x mkvtom4v.sh
)
#!/bin/bash
for file in "$@"; do
HandBrakeCLI -Z "Android Tablet" -c "1-3" -m -O \
--x264-tune film -E copy --decomb -s 1 \
-i "$file" -o "${file/%.mkv/.m4v}"
done
然后用 find 调用它:
find /path/to/directory -name '*.mkv' -exec /path/to/mkvtom4v.sh {} +
一些注意事项:
不要使用反引号 (
);它们已被弃用多年。使用some command
$(some command)
,它更具可读性并且允许嵌套。tr
绝对不是你想要的。它逐个字符地进行翻译。例如,tr aeiou AEIOU
将使所有元音UppErcAsE。tr mkv m4v
将把 every 改为k
a4
。请参阅man tr
(或info tr
) 了解更多详细信息。"${file/%.mkv/.m4v}"
是 bash 特殊的搜索和替换语法。在这种情况下,它的意思是:“取 的值$file
,如果它以.mkv
(%
在此上下文中表示“以”结尾)结尾,则将其替换为.m4v
“。还有很多其他的方法可以编辑变量的值。man bash
并搜索“参数扩展”。使用 GNU find,您可以
{} +
在命令末尾使用-exec
(而不是\;
)。它将被尽可能多的找到的文件名替换。请参阅info find
了解更多详情。