在学习linux的这几天,我发现一个让我困惑的事情:
$ cat abcd
line One
line Two
line Three
$ cat abcd | grep *
$ _ //nothing greped
$ cat abcd | grep ""
line One
line Two
line Three
$ cat abcd | grep "*"
$ _ //nothing greped
“_” 只是光标,不要误会:)
谁能解释一下?谢谢
答案1
shell 将glob*
扩展为当前目录中所有(非点)文件的字母列表。 的参数grep
是搜索表达式和文件列表。 因此grep *
最终使用第一个文件名作为搜索表达式。 您正在其他文件中查找第一个文件的名称(作为正则表达式)。
仅当您未提供任何显式文件名时,Grep 才会搜索标准输入。请参阅:
echo moo | grep . /etc/issue
Handmade Linux for OS/X v 0.001
顺便说一句,*
不是一个有效的正则表达式。正如您所发现的,空搜索表达式匹配所有输入行。匹配所有非空输入行的正则表达式是.
;在正则表达式中,点是一个元字符,它匹配一个字符,除换行符之外的任何字符。 kleene 星号是一个后缀运算符,它允许零次或多次重复上一个正则表达式,因此您经常会看到.*
“任何东西”的正则表达式,但在这种情况下,它是多余的,因为您已经用空搜索字符串匹配了任何东西。
最后,将单个文件保存为单个文件被认为是不好的形式cat
。您不必cat file | grep ""
保存一个进程,也许还有一些轻蔑通过grep
直接读取文件;grep "" file
答案2
将对grep *
当前目录中的文件进行“全局”扩展。
我无法准确预测会发生什么,但*
肯定会与文件名匹配abcd
。因此,您最终可能会在abcd
文件中搜索“abcd”。或者,您可能最终会在其他文件中搜索(按字典顺序)第一个文件的名称。
如果当前目录为空,您最终会搜索*
。但这也不起作用,因为第一个命令行参数是正则表达式,而“*”不是有效的正则表达式。
为了防止通配符,请这样写:
$ cat abcd | grep "*"
...但根据上述原因,这没有任何意义。
要搜索文字“*”字符:
$ cat abcd | grep "\\*"
答案3
在看到命令行参数之前grep
,该参数由 shell 解析。对于 shell 来说,*
是“当前目录中所有非点文件”的通配符。由于 shell 首先处理该参数,因此您的行将变成这样:
cat abcd | grep abcd otherfile zfile
(假设这三个文件位于您当前的目录中)。这就是grep
可以看到其参数的内容,但这不是您想要的。
相反,你可以把模式放在grep
引号中,这样它就是不是由 shell 处理:
cat abcd | grep "*"
这样更好,但仍然不是您想要的:grep
使用正则表达式,而不是 shell 样式的通配符。星号grep
表示“0..n 次重复前一个字符” - 您未指定的字符。接近,但还不够。
如果你想要一个“任意”模式,你正在寻找“0..n 次重复的随意的字符”。后者'.'
在正则表达式中用句点 ( ) 表示:
cat abcd | grep ".*"
那正是您所寻找的。
编辑:另一种情况更容易解释。如果grep ""
你正在寻找一个空的字符串,它作为子字符串存在于任何字符串中。
答案4
Bash 总是将 * 解析为目录中文件的通配符占位符。在您的命令中,bash 将其理解为
cat abcd | grep abcd file1 file2 ...
因此它只显示空输出,因为它不是您要搜索的内容