shell 在考虑调用命令之前执行 glob 扩展。诸如 grep 之类的程序不会做任何事情来防止通配:它们不能。作为这些程序的调用者,你必须告诉 shell 你想将特殊字符如*
和?
传递给程序,而不是让 shell 解释它们。您可以通过将它们放在引号内来做到这一点:
grep -E 'ba(na)* split' *.txt
(在所有名为 <something> 的文件中查找ba split
,bana split
等.txt
)在这种情况下,单引号或双引号都可以解决问题。在单引号之间,shell 什么也不扩展。在双引号之间,$
,`
和\
仍然被解释。您还可以通过在单个字符前面加上反斜杠来保护单个字符免受 shell 扩展。不仅需要保护通配符;例如,在上面,模式中的空格用引号引起来,因此它是参数的一部分,grep
而不是参数分隔符。编写上述代码段的替代方法包括
grep -E "ba(na)* split" *.txt
grep -E ba\(na\)\*\ split *.txt
对于大多数 shell,如果参数包含通配符但模式与任何文件都不匹配,则模式保持不变并传递给底层命令。所以像这样的命令
grep b[an]*a *.txt
根据系统上存在的文件,具有不同的效果。如果当前目录不包含任何名称以 开头的文件b
,则该命令b[an]*a
在名称匹配的文件中搜索模式*.txt
。如果当前目录包含名为baclava
,bnm
和的文件hello.txt
,则该命令扩展为grep baclava bnm hello.txt
,因此它baclava
在两个文件bnm
和中搜索模式hello.txt
。不用说,在脚本中依赖它是个坏主意。在命令行上它偶尔可以节省打字,但这是有风险的。
当您ack .*
在不包含点文件的目录中运行时,shell 会运行ack . ..
. 然后该ack
命令的行为是递归地打印出(当前目录的父目录)下所有文件中的所有非空行(模式.
:匹配任何一个字符) 。..
与 相比,它在当前目录及其子目录ack '.*'
中搜索模式(匹配任何内容)(由于不传递任何文件名参数时的行为)。.*
ack