为什么egrep和grep的行为不同,尽管它们是相同的二进制文件?

问题描述:

$ ls -l /bin/*grep 
lrwxrwxrwx 1 root root  4 2010-06-09 02:56 /bin/egrep -> grep 
lrwxrwxrwx 1 root root  4 2010-06-09 02:56 /bin/fgrep -> grep 
-rwxr-xr-x 1 root root 85060 2007-01-23 02:00 /bin/grep 

$ echo 'hello' | grep -q 'l{2}' && echo YES || echo NO 
NO 

$ echo 'hello' | egrep -q 'l{2}' && echo YES || echo NO 
YES 

在我的系统中,egrep是一个到grep的符号链接,但它们的行为不同。为什么?为什么egrep和grep的行为不同,尽管它们是相同的二进制文件?

grep将通过查看argv[0]来检查其调用。

这里是一个简短的程序来演示:

> cat someprogram.cpp 
#include <iostream> 

int main(int argc, char* argv[]) 
{ 
    std::cout << "Shall behave as " << argv[0] << "." << std::endl; 
} 

体形:

> make someprogram 
g++ someprogram.cpp -o someprogram 

做一个符号链接:

> ln -s someprogram some_other_program 

运行一个:

> ./someprogram 
Shall behave as ./someprogram. 

运行两个:

> ./some_other_program 
Shall behave as ./some_other_program. 

Gnu grepfree和开源软件,因此你可以*地检查the source

由于可执行程序检查argv[0]的值并相应地调整其行为。

因为POSIX说,egrep相当于grep -E,而不是普通的grep,并fgrep相当于grep -F,而不是普通的grep。如果要使grep的行为与egrep的行为相同,请使用grep -E,依此类推。还有约40年的先例问题。

除正则表达式引擎外,其功能相同;通过创建一个库(目前比较常用的方法)或者使用一个检查其名称(argv[0])的单个二进制来确定请求哪个行为来共享代码是有意义的。 (第三种可能是使用单个名称和使用选项来选择不同的行为,这就是gittar这样的命令;单个命令是“界面”,但是通过指定不同的操作可以获得大不相同的行为。 )

有不同的命令的原因是一个悠久的遗产,可以追溯到Unix的早期。简单的旧grep是正则表达式的最早实现之一,随着开发人员对这个特定问题领域的理解得到改进,具有新功能的新工具不断发展。出于向后兼容的原因,这些新功能不能简单地集成到grep(这会改变它的行为),因此新命令有新名称。到POSIX开始规范事情时,grep,egrepfgrep之间的分工已经确立,尽管事后看来,你可能会争辩说至少有一个是多余的。