使用find+xargs+ffmpeg检测损坏MP4时嵌套目录失效问题排查
问题根源与解决方案
你的问题出在shell变量展开和xargs替换符的冲突上,我来拆解清楚:
原命令里你用了-I $让xargs把文件名替换到$的位置,但外层的双引号"ffmpeg -v error -xerror -i $ -f null - || echo $"会让当前shell先解析里面的$——shell会把$当作自己的特殊字符处理(比如直接输出$,或当作未定义变量),这就导致xargs根本没机会把文件名替换进去,最终bash执行的命令里$还是原样,自然只会输出$。
单目录下能正常工作只是巧合:单目录下的文件名没有特殊路径字符,shell解析时没破坏替换逻辑,但这不是可靠的行为。
推荐的正确命令
我给你两个更可靠的写法,都能完美处理含子目录、带空格/特殊字符的文件名:
写法一:用find的-exec直接执行(更简洁高效)
find . -name "*.mp4" -exec bash -c 'ffmpeg -v error -xerror -i "$0" -f null - || echo "$0"' {} \;
find直接对每个找到的MP4文件执行bash命令,{}会被替换成文件名,传递给bash的$0位置参数。- 单引号包裹bash命令,避免当前shell提前解析变量,确保
$0能正确拿到文件名。 ffmpeg的参数-v error -xerror确保只输出错误信息且遇到错误就退出,-f null -表示不生成任何输出文件,只做格式校验。
写法二:保留xargs但替换更安全的占位符
如果你习惯用xargs,可以把替换符改成{}(避免和shell的$冲突),同时用位置参数传递文件名:
find . -name "*.mp4" -print0 | xargs -0 -I {} bash -c 'ffmpeg -v error -xerror -i "$1" -f null - || echo "$1"' _ {}
-print0和xargs -0配合处理含特殊字符的文件名,避免空格、换行符导致的错误。- bash命令里的
$1是传递的文件名,_是bash的$0(占位用,不影响逻辑)。
为什么原命令在单目录下看似正常?
单目录下的文件名都是./xxx.mp4这种短路径,当前shell解析双引号里的$时,可能因为没有对应的变量,直接保留了$字符,xargs刚好能替换成功;但当文件名包含子目录(比如./sub/xxx.mp4)时,路径里的/会让shell的解析逻辑出错,导致替换失败,最终输出$。
内容的提问来源于stack exchange,提问作者Nick Ginanto
相关产品推荐
相关产品推荐

