grep命令匹配异常解析:为何Do*未匹配Documents目录?
ls | grep Do*没匹配到Documents目录? 先明确最核心的一点:shell会先处理命令里的通配符(也就是路径扩展),这一步在grep运行前就完成了——你输入的Do*根本没当成正则表达式传给grep,而是被shell先替换成了当前目录下符合条件的文件名。
拆解两个命令的实际执行过程
1. 执行ls | grep D*时发生了什么
shell先解析D*这个通配符,匹配当前目录下所有以大写D开头的条目,也就是Desktop、Documents、Downloads、Dropbox (Personal)。
这时候实际运行的命令变成了:ls | grep Desktop Documents Downloads Dropbox (Personal)
grep的规则是:第一个非选项参数是匹配模式,后面的参数是要搜索的文件/目录。所以这里Desktop被当成了匹配模式,剩下的几个目录被当成要读取的目标。但grep没法读取目录内容,所以会挨个输出类似grep: Documents: Is a directory的错误提示。
2. 执行ls | grep Do*时发生了什么
shell同样先解析Do*,匹配当前目录下以Do(大写D+小写o)开头的条目。
你的情况里只匹配到了Downloads,说明你的Documents目录名的第二个字符不是小写o(比如可能是大写O,或者拼写有差异)——shell通配符是严格区分大小写、精确匹配前缀的,只要第二个字符不对,就不会被匹配。
扩展后的命令变成:ls | grep Downloads
这时候grep把Downloads当成匹配模式,同时因为没有其他文件参数,它会读取ls输出的内容,找包含Downloads的行。Documents的名称和Downloads完全不沾边,自然不会被匹配到;另外,因为Downloads是目录,grep会尝试读取它(shell把它当作文件参数传进来了),所以会输出grep: Downloads: Is a directory的错误提示。
你误解的核心点
你把shell通配符和grep正则表达式搞混了:
- 如果想让
Do*作为grep的正则表达式(比如匹配以Do开头的行),必须用引号把它括起来,比如ls | grep '^Do'(正则里^表示行开头,Do*其实是匹配D后面跟任意个o的行,不是你想要的前缀匹配)。 - 不加引号的话,
Do*就是shell的通配符,只负责匹配当前目录下的文件名,和ls输出的内容无关。
内容的提问来源于stack exchange,提问作者BLimitless

