别人用通配符是 ls *.log 看看文件,你用通配符是 rm -rf /data/a-z* 清空数据。同一套符号,正邪之分,全在"会不会用"。
一、简介
通配符(Wildcard)是 Shell 用于文件名扩展(globbing) 的特殊字符。它由 Shell 在命令执行之前展开,将包含特殊符号的模式替换为匹配的文件路径列表,再传递给命令。
常见的通配符包括 *、?、\[\]、{} 等。其中 * 匹配任意长度字符串(含空串),? 匹配任意单个字符,... 匹配括号内任一字符或字符范围。
需要特别注意:通配符不是正则表达式。虽然它们有相似的符号,但通配符匹配的是文件名/路径名,而正则表达式匹配的是文本内容。
二、意义及用法
核心意义:让运维人员从"逐个指定文件"进化到"按模式批量操作"。一次 rm *.tmp 顶过十条手动删除命令。
常用通配符速查:
通配符 含义 示例
- * 匹配任意长度字符(含0个) *.log → 所有 .log 文件
- ? 匹配单个字符 file?.txt → file1.txt, fileA.txt
- abc 匹配括号内任一字符 log_123.wal
- a-z 匹配范围内任一字符 backup_202401-12.sql
- !abc 匹配非括号内字符 !0-9*.sh
- {a,b,c} 大括号扩展(非标准通配符) cp file.{txt,log} /backup/
字符类的 POSIX 写法:为避免不同 locale 对范围排序的差异,建议使用 \[:digit:]、\[:alpha:]、\[:lower:] 等字符类。
bash
# 查看所有数字结尾的备份文件
ls backup_[[:digit:]].tar.gz
# 删除所有以数字开头的临时文件(慎用)
rm [0-9]*.tmp
三、经典应用场景
场景一:批量操作日志文件
服务器日志往往按日期或类型命名,通配符可以快速定位:
bash
# 查看所有 2026 年 9 月的日志
ls -lh *202609*.log
# 打包所有 .conf 配置文件
tar czf configs.tar.gz /etc/*.conf
# 删除 7 天前的临时文件(find 配合通配符更安全)
find /tmp -name "*.tmp" -mtime +7 -delete
场景二:设备文件批量查询
/dev/sda、/dev/sda1、/dev/sda2......手动一个个查太慢:
bash
# 查看所有 sda 开头的设备文件
ls -l /dev/sda*
# 或者只查看分区(排除整盘)
ls -l /dev/sda[0-9]
场景三:批量备份/同步
bash
# 复制所有图片文件到备份目录
cp *.jpg *.png /backup/images/
# 使用大括号扩展生成序列目录
mkdir -p /data/backup_{2025,2026}
注意:{} 大括号扩展与通配符有本质区别------它不检查文件是否存在,直接展开成多个字符串。所以 touch file{1...5}.txt 一定会创建 5 个文件,哪怕当前目录一个都没有。
场景四:find 命令中的模式匹配
find 的 -name 参数也支持通配符,但需要注意:find 不经过 Shell 展开,所以通配符需要加引号:
bash
# Shell 先展开,find 收到的是具体文件名列表
find /var/log -name *.log # 可能出问题
# 正确写法:让 find 自己处理模式
find /var/log -name "*.log"
# find 的通配符可以匹配点开头文件(与 Shell 不同)
find . -name "*bashrc" # 会匹配 .bashrc
四、注意事项
- 禁忌一:看不见隐藏文件
Shell 通配符不匹配以 . 开头的文件,除非模式中显式写出点号:
bash
rm * # 不会删除 .bashrc、.profile
tar c * # 不会打包隐藏文件,应该用 tar c .
- 禁忌二:空匹配的陷阱
如果没有文件匹配通配符模式,POSIX 规定保留原样不展开:
bash
# 如果目录下没有 .log 文件
rm *.log
# 实际执行:rm "*.log" → 报错 "No such file or directory"
# 危险场景:脚本中 cp *.txt /backup/
# 如果没有 .txt 文件,cp 会尝试复制一个名为 "*.txt" 的文件
在脚本中,建议使用 shopt -s nullglob 让空匹配展开为"无参数"。
-
禁忌三:* 不匹配 /
Shell 通配符中的 * 和 ? 不会匹配路径分隔符 /。/data/* 只匹配 /data/ 下的直接子项,不递归。
-
禁忌四:通配符展开顺序
Shell 的展开顺序是:大括号扩展 → 波浪号扩展 → 参数/变量扩展 → 命令替换 → 算术扩展 → 单词拆分 → 路径名扩展(通配符) 。这意味着通配符是最后一步,变量中的 * 不会被当作通配符展开:
bash
pattern="*.log"
rm $pattern # 正常:变量值被通配符展开
rm "$pattern" # 错误:引号阻止了通配符展开,Shell 找名为 "*.log" 的文件
- 禁忌五:误删事故案例
社区中流传着一个经典案例:运维人员写了一条命令清理 2023 年的归档日志:
bash
rm /opt/Kingbase/archives/*2023*.wal
本意是删除"日志文件名中含 2023 的"。结果 2023 的通配符语义是"任意字符 + 2023 + 任意字符",把一个名为 archive_2023_backup.wal 的人工灾备副本也一并删除了。
安全习惯:删除前先用 ls 或 echo 预览展开结果:
bash
# 先预览
ls -l /opt/Kingbase/archives/*2023*.wal
# 确认无误再删除
rm /opt/Kingbase/archives/*2023*.wal