相信不少朋友在使用 Bash 进行文件操作时,都遇到过需要在多层目录中查找特定文件的需求。最开始,我习惯使用 find 命令,但 find 命令参数繁多,记忆成本高,而且在某些场景下,效率并不理想。后来我发现了 shopt -s globstar 这个 Bash 内置选项,它配合 ** 递归通配符,简直是文件查找的利器。
今天我们就来深入探讨 shopt -s globstar 的使用,以及它背后的原理。
shopt -s globstar:开启 Bash 的递归通配符功能
shopt 命令用于设置或取消设置 shell 的各种选项。globstar 是 shopt 提供的一个选项,它允许 ** 通配符匹配零个或多个子目录。
默认情况下,** 在 Bash 中并不启用递归匹配。你需要先执行 shopt -s globstar 命令,才能让 ** 发挥作用。
# 开启 globstar 选项
shopt -s globstar
# 查找当前目录下所有子目录中的 .txt 文件
ls -l **/*.txt
# 查找当前目录及其所有子目录中的所有目录
ls -d **/ # -d 选项用于显示目录本身,而不是目录内容
如果想关闭 globstar,可以使用 shopt -u globstar 命令:
# 关闭 globstar 选项
shopt -u globstar
底层原理:Bash 的路径名扩展
globstar 的实现依赖于 Bash 的路径名扩展(Pathname Expansion)功能。当 Bash 遇到包含通配符的命令时,它会将通配符扩展成匹配的文件或目录列表。globstar 选项增强了这种扩展能力,使得 ** 可以递归地匹配子目录。
简单来说,Bash 会按照以下步骤处理包含 ** 的命令:
- 扫描目录: Bash 从当前目录开始,扫描所有文件和子目录。
- 递归匹配: 对于每个子目录,Bash 都会递归地进入,并重复扫描过程。
- 应用通配符: Bash 将扫描到的文件和目录与通配符进行匹配。
- 生成列表: Bash 将所有匹配的文件和目录组成一个列表,并将其作为命令的参数。
正是由于这种递归匹配的特性,shopt -s globstar 配合 ** 才能轻松实现多层目录的文件查找。
代码示例:实用技巧与场景应用
查找所有 .conf 文件并备份
shopt -s globstar
for file in **/*.conf; do
cp "$file" "$file.bak" # 使用引号防止文件名包含空格导致的问题
done
统计所有 .log 文件的总大小
shopt -s globstar
du -ch **/*.log | tail -n 1 # du 命令用于统计文件大小,-c 显示总计, -h 以人类可读的方式显示大小
使用 find 命令配合 globstar 实现更复杂的查找
虽然 globstar 很方便,但在某些复杂场景下,可能还需要结合 find 命令使用。例如,查找特定时间范围内修改过的文件:
shopt -s globstar
find . -path './node_modules' -prune -o -name '*.js' -type f -mtime -7 -print # 查找最近 7 天内修改过的 .js 文件,并排除 node_modules 目录
# -path './node_modules' -prune 用于排除 node_modules 目录
# -o 表示或的关系
# -name '*.js' 匹配文件名
# -type f 只查找文件
# -mtime -7 最近 7 天内修改过
# -print 打印结果
这里我们结合了 find 命令的 -path 和 -prune 参数,可以有效地排除不需要搜索的目录,提高搜索效率。这在大型项目中尤为重要,例如,在 Nginx 配置中,我们经常需要排除一些临时目录或者日志目录。
查找并批量删除空目录
结合 find 和 rmdir 命令,可以方便地删除空目录:
find . -type d -empty -print -exec rmdir {} \; # 查找空目录并删除
# -type d 只查找目录
# -empty 查找空目录
# -exec rmdir {} \; 对查找到的每个目录执行 rmdir 命令
实战避坑:使用 globstar 的注意事项
- 性能问题: 在大型目录结构中使用
globstar可能会导致性能问题,因为 Bash 需要扫描大量的目录和文件。尽量避免在根目录下使用**,或者结合find命令的-path和-prune参数排除不需要搜索的目录。 - 文件名包含空格: 如果文件名包含空格,需要使用引号将文件名括起来,以防止 Bash 将其分割成多个参数。
- 递归深度限制: Bash 可能会对递归深度有限制。如果你的目录结构非常深,可能会遇到递归深度超限的问题。可以尝试调整
GLOBIGNORE变量来控制匹配行为,或者使用find命令代替。 - 与其他通配符的配合:
globstar可以与其他通配符(如*、?、[])配合使用,实现更灵活的匹配。 - 注意安全性: 在执行删除操作前,务必仔细检查匹配的文件和目录,避免误删重要数据。
总而言之,shopt -s globstar 是 Bash 中一个非常实用的选项,它可以极大地简化文件查找操作。但在使用时,需要注意性能问题和潜在的风险,并根据实际情况选择合适的解决方案。例如,在高并发的 Nginx 服务器上,频繁的磁盘 I/O 可能会影响服务器的性能,所以需要谨慎使用。
冠军资讯
程序员石头