<p>find 命令中 搜不到文件,因为 shell 不展开转义的 ,find 将其视为字面量而非通配符;正确写法是用单引号保护:find . -name '*.log',多后缀需用 -o 连接。</p>

find 命令里用 * 为什么经常搜不到文件
因为 find 默认不展开 shell 通配符,* 会被当作字面量传给 find,而不是让 shell 先匹配路径。你写 find . -name *.log,如果当前目录没有 .log 文件,shell 就把 *.log 原样交给 find,而 find 会去查文件名「就是 * 字符加 log」的文件——当然找不到。
- 正确写法是加单引号:
find . -name '*.log',防止 shell 提前展开 - 如果想匹配多个后缀,不能写
-name '*.log|*.txt',要用-o拼接:find . \( -name '*.log' -o -name '*.txt' \) -
find的-name只支持?、*、[...],不支持正则;要正则得用-regex,但注意它匹配的是**完整路径**,不是仅文件名
ls 和 cp 这类命令里 * 看似好用,其实有陷阱
它们依赖 shell 展开通配符,一旦没匹配到任何文件,有些 shell(如 bash)默认原样传入,导致 ls *.nonexist 报错 No such file or directory;而 zsh 默认报错并中止,更严格。
- 安全做法是先测试通配是否生效:
echo *.log,看输出是不是你预期的文件列表 - 避免在脚本里直接用
cp *.txt /dest/:万一没匹配到,就变成cp *.txt /dest/,可能误删或报错;可用shopt -s nullglob(bash)让空匹配返回空,或改用find ... -exec cp {} /dest/ \; -
rm *.tmp在空目录下可能误删当前目录下的.tmp文件(如果存在),更危险的是,若只有.tmp隐藏文件,*默认不匹配点开头的文件——除非你开了dotglob
grep 里写 * 不是通配,是正则量词
新手常把 grep *.log 当成“搜含 .log 的行”,结果发现行为诡异——因为 shell 先把 *.log 展开成当前目录所有 .log 文件名,再把这些文件名当 grep 的 pattern 和 target 混着传,极大概率报错或误匹配。
- 搜文本内容用
grep '\.log'(注意点要转义),不是*.log - 想搜多个模式,用
-e:grep -e 'error' -e 'warn' *.log - 如果真要模糊匹配行首/行中/行尾,用正则:
grep '^ERROR.*timeout$',这里的*是正则语法,和文件名通配无关
bash 的 [[ ]] 条件判断里,= 和 == 都支持通配,但 test [ ] 不支持
这是最容易混淆的兼容性坑:[ "$file" = "*.log" ] 是字面比较,不会通配;而 [[ "$file" = *.log ]] 才真正做模式匹配。
- 必须用
[[ ]],不能用[ ],否则*没意义 - 变量值里含空格或特殊字符时,
[[ $file = *.log ]]依然安全,不用引号;但[[ "$file" = *.log ]]也 OK,只是别写成[[ "$file" = "*.log" ]](引号会让通配失效) - 如果要正则匹配,用
=~:[[ $line =~ ^[0-9]{4}-[0-9]{2} ]],注意右边是正则,不是 glob
通配符看着简单,实际每层工具(shell、find、grep、test)对它的解释规则都不同,最常出问题的是「以为自己在用通配,其实被 shell 展开了」「以为在用正则,其实只是 glob」——盯住你正在用的命令手册里关于 pattern matching 的那一小节,比背口诀管用。










