执行`ls *.c`时系统内部流程及shell globbing疑问解析
关于Linux文件名扩展(Globbing)的解惑
嘿,这个问题问得特别到位——很多刚深挖Linux命令行机制的朋友都会在这一步踩坑!先给你吃颗定心丸:你之前对ls核心调用的理解完全正确:当ls没有指定具体文件时,确实会通过opendir()、readdir()遍历目录,必要时调用stat()获取文件元信息。
而你困惑的strace ls *.c和strace ls的差异,核心原因只有一个:文件名扩展(globbing)是你的shell(比如bash、zsh这类交互式shell)提前完成的,根本轮不到ls来处理。
具体拆解两种场景:
- 当你执行
strace ls时,shell直接把ls作为命令传递给内核启动,此时ls没有收到任何文件名参数,所以它会默认遍历当前工作目录,这就是你看到opendir()、getdents()等系统调用的原因。 - 当你执行
strace ls *.c时,shell在启动ls之前,会先识别到*.c这个通配符:它会主动遍历当前目录,找出所有以.c结尾的文件,把*.c替换成这些匹配到的文件名列表(比如a.c b.c test.c),然后再把这个完整的文件名列表作为参数传给ls。
换句话说,ls拿到的已经是现成的、匹配好的文件名,它根本不需要自己去做通配符匹配,自然也就不会有相关的系统调用了。
你可以用两个小实验验证这个逻辑:
- 执行
echo *.c,会直接输出当前目录下所有.c文件的名称——这就是shell提前处理通配符的直接证据。 - 执行
strace ls '*.c'(注意用单引号把通配符括起来),此时shell会把*.c当成普通字符串传递给ls,ls就会尝试查找名为*.c的文件,你会在strace里看到它调用stat("*.c", ...)的失败记录,同时终端会提示ls: cannot access '*.c': No such file or directory。
内容的提问来源于stack exchange,提问作者akmal




