情况:
- 运行 macOS 10.13.6 并使用 bash 5.0.17(1)
- 许多包含多个文件的子目录。
- 需要过滤掉子目录中具有特定扩展名(.avi)的文件。
- 需要处理所有 .avi 文件并使用 .mp4 重新混合
ffmpeg
。ffmpeg
使用以下语法进行重新混合:ffmpeg -i in.avi -c copy out.mp4
- 输出格式:与源 .avi 文件位于同一文件夹中,并使用相同的文件名(除了 .avi 扩展名)
文件结构示例:
$ find . -maxdepth 2
.
./abc
./abc/abc.avi
./xyz
./xyz/xyz.avi.mp4
./123
./123/123.avi
在这种情况下,我想过滤掉文件./abc/abc.avi
和./123/123.avi
,我可以使用正则表达式 和 来做到这一点find
:
$ find -E . -iregex ".*\.avi"
./abc/abc.avi
./123/123.avi
所需的重新混合.mp4
输出文件名将是:
./abc/abc.mp4
./123/123.mp4
我怎么能够:
- 使用脚本,通过一个命令将所有这些
.avi
文件重新混合到.mp4
容器中?我不确定如何将 的输出通过管道传输find
到 的输入ffmpeg
,并同时指定所需的输出文件名。 - 删除原始
.avi
文件,但前提是 remux 成功?
答案1
我不是 Arch Linux 的用户ffmpeg
,我是在bash
Arch Linux 的环境中写这个答案的,但是你的两个要求可以在 FreeBSD 和 MacOS-X 上得到满足,例如:
$ from=avi; to=mp4;
$ find -E . -type f -iregex ".*\.avi" -execdir \
sh -c 'file=$(basename $3); (ffmpeg -i $file.$1 -c copy $file.$2) 2>/dev/null && \rm $3' shellproc "$from" "$to" {} \;
在上面的一行中:
- 我
-type f
之前包括了-iregex ...
.它应该通过stat
仅“常规文件”类型的文件来节省您的时间。 $1
代表$from
$2
代表$to
$3
代表,即你的命令{}
的结果find
shellproc
in...shellproc "$from" "$to" {} \;
只是一个任意标记,用于标识使用以下命令执行的 shell 进程sh -c 'file=$(basename $3); (ffmpeg -i $file.$1 -c copy $file.$2) 2>/dev/null && \rm $3'
。该标签将为所述 shell 输出的任何错误消息添加前缀。这就是它的功能。
有几种可能的方法可以实现您想要的功能。我建议你看一下回答作者:Kusalananda,了解(更多)更多关于find ... -exec...
的语法。
答案2
归功于Cbhihe的回答,因为它让我走上了正确的道路。由于基线在 Mac 上的工作方式以及文件名中空格的处理,我需要更改一些内容。
macOSfind
使用有点特殊的语法。您可以使用以下单行:
find -E . -type f -iregex ".*\.avi" -execdir bash -c 'in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"' shellproc {} \;
find -E . -type f -iregex ".*\.avi"
搜索文件:.
表示搜索当前目录,-E
表示允许使用正则表达式的扩展查找,-iregex ".*\.avi"
搜索此路径中的所有“.aviz”文件,包括子目录。
-execdir bash -c '<COMMAND>' shellproc {} \;
使用 bash shell 对每个搜索结果执行命令,从与搜索结果相同的目录执行。文件名作为参数 $1 传递。in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"
定义输入和输出文件名,运行 ffmpeg 进行重新混合并抑制详细的 ffmpeg 输出,并仅在重新混合成功完成时删除输入文件。
在 Linux 系统上,find
语法略有不同:
find . -type f -regex ".*\.avi" -execdir bash -c 'in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"' shellproc {} \;