为什么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 grep
是free和开源软件,因此你可以自由地检查the source。
答
由于可执行程序检查argv[0]
的值并相应地调整其行为。
答
因为POSIX说,egrep
相当于grep -E
,而不是普通的grep
,并fgrep
相当于grep -F
,而不是普通的grep
。如果要使grep
的行为与egrep
的行为相同,请使用grep -E
,依此类推。还有约40年的先例问题。
答
除正则表达式引擎外,其功能相同;通过创建一个库(目前比较常用的方法)或者使用一个检查其名称(argv[0]
)的单个二进制来确定请求哪个行为来共享代码是有意义的。 (第三种可能是使用单个名称和使用选项来选择不同的行为,这就是git
和tar
这样的命令;单个命令是“界面”,但是通过指定不同的操作可以获得大不相同的行为。 )
有不同的命令的原因是一个悠久的遗产,可以追溯到Unix的早期。简单的旧grep
是正则表达式的最早实现之一,随着开发人员对这个特定问题领域的理解得到改进,具有新功能的新工具不断发展。出于向后兼容的原因,这些新功能不能简单地集成到grep
(这会改变它的行为),因此新命令有新名称。到POSIX开始规范事情时,grep
,egrep
和fgrep
之间的分工已经确立,尽管事后看来,你可能会争辩说至少有一个是多余的。