grep 命令的本质是什么?

grep 命令的本质是什么?

我想使用通配符“*”来 grep 所有 .txt 文件。
我尝试了这个命令(以及没有引号“”)但失败了。

ls | grep "*.txt"

有趣的是,如果我在 grep 命令中放入与目录中的 .txt 文件相对应的另一个字符,它就会起作用

>>ls | grep s*.txt
sample.txt

我知道这ls *.txt会起作用,但我对 grep 命令的性质有点惊讶。有人可以帮助我为什么会发生这种情况吗?

是不是因为grep用了正则表达式,请帮忙。

答案1

在正则表达式中,*意味着“任意数量的前一项”,而不是“任意数量的任意字符”,就像在 shell 模式中那样。并.表示“任何单个字符”。因此,要查找“任何内容,后跟文字.txt”,您可以使用.*\.txt.或者只是\.txt,因为通常正则表达式匹配会在行中的任何位置搜索匹配项。然后,\.txt还会匹配类似 的文件名foo.txtgz,因为.txt不必位于末尾。您需要\.txt$将模式锁定到行尾。

正则表达式*.txt要么是无意义的、是错误的,要么是查找字面星号,具体取决于实现以及您使用的是基本正则表达式 ( grep) 还是扩展正则表达式 ( grep -E)。最好不要使用它。

另一方面,s*.txt将查找“任意数量的字母s,然后是任何单个字符,然后是文字txt”。这是一个更有效的正则表达式,但是...仍然不匹配sample.txt

相反,第二个命令中发生的情况是,由于s*.txt未加引号,因此 shell 会在看到它s*.txt之前展开grep它。如果唯一匹配的文件是sample.txt,则grep在 的输出中查找该文件ls。 (如果有多个匹配的文件名,第一个将被视为模式,其余的将作为文件名进行grep读取。在这种情况下,它将忽略来自管道的输入。)


但是,ls也可以获取文件列表,因此虽然您可以使用

ls | grep '\.txt'

要获取任何.txt文件,使用它可能会更容易

ls *.txt 

反而。

答案2

部分原因是因为grep使用了正则表达式(事实上,这就是re名称中的代表的意思 - 它是G全局的r规则的e表达p打印)。

正则表达式中的通配符与shell 通配符中的通配符*不同。*

在正则表达式中,*表示“零个或多个先前定义的对象”。然而,.通配符,意思是“一个字符”。

在 shell glob 中,*表示“零个或多个字符”。 .根本不是通配符。

当您grep查找模式时"*.txt",您正在寻找零个或多个任何内容,后跟一个字符,最后是文字字符串txt

当您grep使用模式"s*.txt"m you are looking for a literals , followed by zero or mores s, followed by any character, followed by the literal stringtxt`.

这就是为什么您在正则表达式中会发现的一个常见现象是.*,这意味着“任何字符之一后跟零个或多个任何字符”。正则表达式“实际上是除零字符之外的任何字符组合”。

当您ls *.txt告诉 shell“查找与 glob 模式匹配的任何文件名”时*.txt,请在此处列出它们,并将它们作为参数提供给ls命令。

答案3

请注意 grep 正在搜索文件内容第一个参数是搜索模式,其他参数解释为要查看的文件

使用grep -H -o标志或将其放入grep脚本中并运行它以bash -x script查看 shell globs 在作为参数传递之前如何扩展时,它会变得更加清晰

相关内容