BASH中for遍历通配符无匹配文件时仍执行循环的原因
问题根因
这是Bash通配符(Globbing)的默认行为:当通配符规则没有匹配到任何真实存在的文件时,shell不会将通配符展开为空值,而是会把包含通配符的原始字符串本身作为展开结果返回。
你代码里的for i in /drvsoft/shred*.log逻辑,在对应路径下没有任何匹配shred*.log规则的文件时,循环拿到的i取值就是字面量字符串/drvsoft/shred*.log,因此循环体必然会执行1次,计数器lc从0累加到1,最终输出1。
你执行ls /drvsoft/shred*.log时报文件不存在,本质也是同一个逻辑:shell把未匹配到文件的通配符原样传给ls命令,ls去查找文件名真的包含*字符的/drvsoft/shred*.log文件,自然找不到,两个现象不存在矛盾。
修复方案
你可以根据场景选以下任意一种方式规避这个特性带来的不符合预期的行为:
- 开启
nullglob选项:开启后通配符无匹配时会直接展开为空列表,for循环不会执行任何循环体,是最简洁的方案。修正后的代码示例:
function stupid() { local lc=0 # 开启通配符无匹配返回空的特性 shopt -s nullglob for i in /drvsoft/shred*.log; do (( lc+=1 )) done echo $lc }
- 循环体内加存在性判断:不修改shell全局选项,在循环体开头判断当前路径是否真实存在,不存在就跳过本次循环,兼容性更好:
function stupid() { local lc=0 for i in /drvsoft/shred*.log; do # 路径不存在直接跳过 [ -e "$i" ] || continue (( lc+=1 )) done echo $lc }
注意:通配符无匹配时返回原始字符串是POSIX标准规定的shell默认行为,并非Bash独有bug,sh、ksh等传统shell默认都遵循该逻辑。
内容的提问来源于stack exchange,提问作者BenG
相关产品推荐
相关产品推荐

