arv*_*vil 7 debian find shell-script recursive for
我有一个想法,即运行 bash 脚本来检查某些条件并使用ffmpeg将我目录中的所有视频从任何格式转换为.mkv它,它运行良好!
问题是,我不知道for file in循环不能递归地工作(/sf/ask/324721211/)
但我几乎不理解“管道”,我期待看到一个例子并清除一些不确定性。
我想到了这个场景,我认为这对我的理解有很大帮助。
假设我有这个 bash 脚本片段:
for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Run Code Online (Sandbox Code Playgroud)
它的作用是,对于当前目录,搜索任何*.mkv *avi *mp4 *flv *ogg *mov然后声明输出具有其扩展名,.mkv然后删除原始文件,然后输出应保存到原始视频所在的同一文件夹中。
如何将其转换为递归运行?如果我使用find,在哪里声明变量$file?你应该在哪里申报$target?都是find真的单行吗?我真的需要将文件传递给一个变量$file,因为我仍然需要运行条件检查。
并且,假设(1)成功,如何确保满足“然后输出应保存到原始视频所在的同一文件夹”的要求?
使用 POSIX 查找:
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o \
-name '*ogg' -o -name '*mov' \) -exec sh -c '
for file do
target="${file%.*}.mkv"
echo ffmpeg -i "$file" "$target"
done' sh {} +
Run Code Online (Sandbox Code Playgroud)
替换echo为您要使用的任何命令。
如果你有 GNU find 或 BSD find,你可以使用-regex:
find . -regex '.*\.\(mkv\|avi\|mp4\|flv\|ogg\|mov\)'
Run Code Online (Sandbox Code Playgroud)
你有这个代码:
Run Code Online (Sandbox Code Playgroud)for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done
它在当前目录中运行。要将其转换为递归过程,您有几个选择。最简单的(IMO)是find按照您的建议使用。for 的语法find非常“非 UNIX-like”,但这里的原则是每个参数都可以与 AND 或 OR 条件一起应用。在这里,我们要说“如果这个文件名匹配或者那个文件名匹配那么打印它”。文件名模式被引用,以便 shell 无法获取它们(请记住,shell 负责扩展所有未引用的模式,所以如果您有一个未引用的模式,*.mp4并且您janeeyre.mp4在当前目录中有一个,shell 将替换*.mp4为匹配,并且find会看到-name janeeyre.mp4而不是您想要的-name *.mp4;如果*.mp4匹配多个名称...)。括号以 为前缀,\以防止 shell 尝试将它们作为子 shell 标记(如果愿意,我们可以引用括号代替:)'('。
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print
Run Code Online (Sandbox Code Playgroud)
需要将其输出输入到while循环的输入中,该循环依次处理每个文件:
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
ffmpeg -i "$file" "$target" && rm -rf "$file"
done
Run Code Online (Sandbox Code Playgroud)
现在剩下的就是用管道将这两个部分连接在一起,|以便 的输出find成为while循环的输入。
在您测试此代码时,我建议您在ffmpeg和 前rm加上前缀,echo以便您可以查看将执行的内容 - 以及使用哪些路径。
这是最终结果,包括echo我推荐用于测试的语句:
find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print |
while IFS= read file ## IFS= prevents "read" stripping whitespace
do
target="${file%.*}.mkv"
echo ffmpeg -i "$file" "$target" && echo rm -rf "$file"
done
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2397 次 |
| 最近记录: |