Shell 中的 Globbing:原理、使用方法与实现解析
在 Unix Shell(如 Bash、Zsh)中,globbing 是指 文件名模式匹配(filename pattern matching),它允许用户使用特殊的通配符(wildcards)来匹配多个文件,而不需要手动列出所有文件名。这一功能是 Shell 解析命令时的一个重要步骤,极大地提高了命令行操作的灵活性。
1. 什么是 Globbing?
Globbing 是 Shell 解释用户输入的命令时,将包含通配符的模式 扩展为符合匹配规则的文件名列表 的过程。例如:
ls *.txt
在执行 ls *.txt
时,Shell 不会将 *.txt
直接传递给 ls
,而是会 先解析 *.txt
并匹配当前目录下的所有 .txt
文件,然后把结果传递给 ls
命令。例如,当前目录下有:
file1.txt file2.txt file3.log
则:
ls *.txt
实际上等价于:
ls file1.txt file2.txt
其中 file3.log
因不符合 *.txt
的模式匹配规则而被排除。
2. Globbing 的常见通配符
Shell 的 globbing 机制支持多种 通配符(wildcards),常见的有以下几种:
通配符 | 作用 | 示例 | 匹配内容 |
---|---|---|---|
* | 匹配 任意数量 的字符(包括 0 个字符) | *.txt | a.txt 、b.txt 、test.txt |
? | 匹配 任意单个字符 | file?.txt | file1.txt 、file2.txt ,但不匹配 file10.txt |
[abc] | 匹配 [] 内的 任意一个字符 | file[12].txt | file1.txt 、file2.txt |
[a-z] | 匹配 某个范围内的字符 | file[a-z].txt | filea.txt 、fileb.txt |
{a,b,c} | 匹配 逗号分隔的任意一个模式 | file{1,2,3}.txt | file1.txt 、file2.txt 、file3.txt |
** (仅 Bash 4.0+) | 递归匹配所有子目录 | **/*.txt | 匹配当前目录及所有子目录中的 .txt 文件 |
3. Globbing 的执行流程
在 Shell 处理用户输入的命令时,globbing 是命令解析(parsing)过程中的一个步骤。执行流程如下:
- 用户输入命令(例如
ls *.txt
)。 - Shell 解析命令:
- 如果命令行包含通配符(如
*
),Shell 进入 globbing 处理。 - Shell 读取当前目录下的文件列表,并 匹配符合规则的文件名。
- 如果命令行包含通配符(如
- Shell 替换通配符模式:
*.txt
被替换为所有匹配的文件名,如file1.txt file2.txt
。
- Shell 执行最终命令:
ls file1.txt file2.txt
注意:如果没有任何文件匹配通配符模式,大多数 Shell 会直接返回原始模式,如:
echo *.xyz
如果
*.xyz
没有匹配的文件,Bash 会直接输出*.xyz
,而不会报错。
4. Globbing 与 正则表达式 的区别
Globbing 并不是正则表达式,它们有以下主要区别:
特性 | Globbing | 正则表达式 |
---|---|---|
作用 | 文件名匹配 | 处理文本模式匹配 |
* 含义 | 匹配 任意字符(包括空字符) | 匹配 前一个字符 0 次或多次 |
? 含义 | 匹配 任意单个字符 | 匹配 前一个字符 0 或 1 次 |
. 含义 | 作为普通字符匹配 | 代表 任意单个字符 |
示例:
ls *.txt # 使用 globbing,匹配所有 .txt 结尾的文件
grep 'a.*b' file.txt # 使用正则表达式,匹配 'a' 到 'b' 之间的任何字符
5. 禁用 Globbing
有时候,我们希望 Shell 不要 自动展开通配符,而是让命令接收到原始的 *
或 ?
等字符。可以使用以下方法:
- 使用单引号
''
echo '*.txt' # 输出 *.txt,而不是匹配的文件列表
- 使用
set -f
关闭 globbingset -f echo *.txt # 直接输出 *.txt set +f # 重新开启 globbing
6. Shell 中的 Globbing 实现
Globbing 在 Shell 内部是如何实现的呢?主要分为以下几步:
- 读取命令:Shell 读取用户输入的命令字符串。
- 解析通配符:
- 遍历当前目录文件列表。
- 依次对文件名进行 模式匹配(Pattern Matching)。
- 使用 字符串匹配算法 进行匹配,如:
*
进行贪心匹配(Greedy Match)。?
进行单字符匹配。[a-z]
进行范围匹配。
- 替换匹配项:
- 匹配的文件列表替换原始通配符字符串。
- 执行命令:Shell 执行替换后的命令。
Shell 通常使用 系统调用 opendir()
和 readdir()
访问目录并进行匹配。
7. 编写 C 代码实现简单的 Globbing
下面是一个使用 fnmatch()
函数进行 Shell 风格模式匹配的 C 代码示例:
具体原理和代码解析请看笔者的另一篇博客: 深入解析 fnmatch():C 语言中的模式匹配函数(中英双语)
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <fnmatch.h>void list_matching_files(const char *pattern) {struct dirent *entry;DIR *dir = opendir(".");if (!dir) {perror("opendir");return;}while ((entry = readdir(dir)) != NULL) {if (fnmatch(pattern, entry->d_name, 0) == 0) {printf("%s\n", entry->d_name);}}closedir(dir);
}int main() {list_matching_files("*.c"); // 匹配当前目录下的所有 .c 文件return 0;
}
运行示例:
$ gcc globbing.c -o globbing
$ ./globbing
main.c
utils.c
shell.c
8. 结论
Globbing 是 Shell 解析命令的重要步骤,主要用于 文件名匹配,其实现涉及 字符串匹配算法、系统目录读取 等技术。用户可以利用 通配符 灵活地批量操作文件,但要注意它与 正则表达式 的区别。此外,用户可以通过 单引号 或 set -f
禁用 Globbing,使 Shell 直接传递原始字符串。理解 Globbing 的原理可以帮助我们更高效地使用 Shell 命令,提高自动化任务的执行效率。
这篇博客详细介绍了 Globbing 的概念、用法、实现原理、C 代码示例,希望能帮助你更深入地理解这个 Shell 机制! 🚀
Shell Globbing: Principles, Usage, and Implementation
Globbing in Unix Shell (such as Bash, Zsh) refers to filename pattern matching, where users can use special wildcard characters to match multiple files without manually listing their names. This feature enhances the flexibility of command-line operations.
1. What is Globbing?
Globbing is the process where the Shell expands wildcard patterns into matching filenames before executing a command.
For example, consider the command:
ls *.txt
Instead of passing *.txt
as an argument to ls
, the Shell first expands the pattern by searching for files in the current directory that match the pattern. If the directory contains:
file1.txt file2.txt file3.log
then the command:
ls *.txt
is actually executed as:
ls file1.txt file2.txt
while file3.log
is ignored because it does not match *.txt
.
2. Common Wildcards in Globbing
Shell globbing supports several wildcards for flexible pattern matching:
Wildcard | Description | Example | Matches |
---|---|---|---|
* | Matches any number of characters (including none) | *.txt | a.txt , b.txt , test.txt |
? | Matches any single character | file?.txt | file1.txt , file2.txt (not file10.txt ) |
[abc] | Matches any single character in brackets | file[12].txt | file1.txt , file2.txt |
[a-z] | Matches any character in the range | file[a-z].txt | filea.txt , fileb.txt |
{a,b,c} | Matches any of the comma-separated patterns | file{1,2,3}.txt | file1.txt , file2.txt , file3.txt |
** (Bash 4.0+) | Recursively matches files in subdirectories | **/*.txt | All .txt files in the directory tree |
3. How Globbing Works Internally
When a user enters a command, Shell processing follows these steps:
- User inputs a command (e.g.,
ls *.txt
). - Shell scans for wildcards:
- If a command argument contains a wildcard (
*
,?
, etc.), Shell performs globbing. - It retrieves the list of files in the current directory.
- It matches filenames against the pattern.
- If a command argument contains a wildcard (
- Shell replaces the pattern with matching filenames:
- If
*.txt
matchesfile1.txt file2.txt
, the final command becomes:ls file1.txt file2.txt
- If
- Shell executes the command.
Note: If no files match, some shells return the original pattern (e.g.,
echo *.xyz
outputs*.xyz
).
4. Difference Between Globbing and Regular Expressions
Globbing is not the same as regular expressions. Key differences:
Feature | Globbing | Regular Expressions |
---|---|---|
Purpose | Matches filenames | Matches text patterns |
* | Matches any characters | Matches previous character zero or more times |
? | Matches one character | Matches previous character zero or one time |
. | Treated as a normal character | Matches any character |
Example:
ls *.txt # Uses globbing to list all .txt files
grep 'a.*b' file.txt # Uses regex to match 'a' followed by 'b'
5. Disabling Globbing
To prevent Shell from expanding wildcards, use:
- Single quotes (
''
):echo '*.txt' # Outputs *.txt without expansion
- Disable globbing with
set -f
:set -f echo *.txt # Outputs *.txt set +f # Re-enables globbing
6. How Globbing is Implemented in Shell
Internally, globbing is handled in these steps:
- Shell reads the command string.
- Pattern matching against directory contents:
- It retrieves files using system calls like
opendir()
andreaddir()
. - It applies pattern matching algorithms.
- It retrieves files using system calls like
- Matches are substituted before executing the command.
7. Implementing Globbing in C
The following C program demonstrates pattern matching using fnmatch()
, which applies glob-style matching:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <fnmatch.h>void list_matching_files(const char *pattern) {struct dirent *entry;DIR *dir = opendir(".");if (!dir) {perror("opendir");return;}while ((entry = readdir(dir)) != NULL) {if (fnmatch(pattern, entry->d_name, 0) == 0) {printf("%s\n", entry->d_name);}}closedir(dir);
}int main() {list_matching_files("*.c"); // Matches all `.c` files in the directoryreturn 0;
}
Example Output
If the directory contains main.c utils.c shell.c
, running:
$ gcc globbing.c -o globbing
$ ./globbing
main.c
utils.c
shell.c
8. Conclusion
Globbing is a key feature of Shell parsing, allowing users to efficiently match filenames using wildcards. It differs from regular expressions and is processed before executing commands. Understanding globbing helps users write more efficient command-line operations and scripts. It is implemented at the Shell level using directory scanning and pattern matching algorithms.
Mastering globbing enables more effective batch file operations, automation, and scripting in Unix-based systems! 🚀
后记
2025年2月4日于山东日照。在GPT4o大模型辅助下完成。