假设一个目录有 100 个以字母“a”开头的文件。
如果我grep <some string> a*
从终端执行 a,shell 将如何处理这个问题?
它会扩展正则表达式,获取以 a 开头的所有文件的列表,并按顺序对每个文件进行 grep 吗?或者还有其他办法吗?
假设我有一个以“a”开头的上述文件名数组。如果我编写一个 for 循环并在 shell 脚本或 ac 程序中自己进行迭代,会花费更多/更少的时间吗?
答案1
a*
首先,有一点挑剔:像普通 shell 语法一样的字符串是一个 glob,它的工作方式与正则表达式不同。
总体而言,shell 解释器(即 bash)将字符串扩展a*
为与模式匹配的每个文件名的列表a*
。然后,这些将成为命令行参数的一部分单身的的实例grep
(对于程序员来说,所有扩展的单词都作为单独的字符串进入 的参数argv
)main
。然后,该grep
命令以它选择的任何方式解析参数,并将grep
这些参数解释为文件名、选项、选项参数、正则表达式等,并采取适当的操作。一切都是按顺序发生的(据我所知,没有grep
实现使用多个线程)。
如果您在 shell 脚本中实现循环来执行相同的操作,则几乎肯定会比上述过程慢,原因如下。如果为每个文件生成一个新的 grep 进程,由于进程创建的开销不必要地增加,它肯定会变慢。如果您在 shell 脚本中自己构建参数列表并使用 的单个实例grep
,那么您在 shell 中执行的任何操作仍然会变慢,因为 shell 命令必须解释(通过 bash),这会增加额外的代码层,并且您将只是重新实现 bash 在编译代码中已经在内部更快地完成的事情。
至于用 C 自己编写,您可能可以轻松获得与第一段中描述的过程相当的性能,但您不太可能比当前的 grep/bash 实现获得足够的性能增益来证明时间是合理的无需深入研究特定于机器的性能优化或牺牲可移植性。也许您可以尝试提出一个任意可并行化的版本grep
,但即使这样也可能无济于事,因为您更有可能受到 I/O 限制而不是 CPU 限制。对于大多数“正常”用途来说,全局扩展和 grep 已经“足够快”。
答案2
是的,它将扩展为文件列表并将结果列表提供给程序grep
。至少这就是man bash
小节中所说的路径名扩展。
正如您提到的,在简单情况下还有另一种使用扩展的方法:编写grep <some_string> a
和按下之前*
, 按ESC。这将在命令行中展开匹配文件的列表,因此您可以在按 之前验证列表是否正常Enter。
至于你问题的第二部分,这要看情况。如果您打算编写一个 for 循环,依次在每个文件上运行 grep,那么它肯定会更慢,因为 grep 程序不会运行一次,而是每个文件运行一次。然而,什么是重要的是要记住,有一定的限制您可以使用命令行参数的扩展长度,尽管它通常相当长。要看到这一点,您可以尝试grep adasdsadf /usr/*/*/* >/dev/null
。