3

我有一个大约 10KB 的文本文件 foobar.txt,没有那么长。然而,在高性能 Linux 机器上,以下匹配搜索命令大约需要 10 秒。

bash>shopt -s extglob
bash>[[ `cat foobar.txt` == ?(*[[:print:]])foobar ]]

不匹配:foobar.txt 中的所有字符都是可打印的,但没有字符串“foobar”。

搜索应该尝试匹配两个备选方案,每个备选方案都不匹配:

"foobar"

那是瞬间的

*[[:print:]]foobar

- 应该是这样的:

应该一次一个字符地扫描文件,每次,检查下一个字符是否

[[:print:]]foobar

这也应该很快,每个字符都不应该花费一毫秒。

事实上,如果我放弃?,也就是做

bash>[[ `cat foobar.txt` == *[[:print:]]foobar ]]

瞬间的。但这只是上面的第二种选择,没有第一种。

那为什么这么长??

4

3 回答 3

6

bash 中的 glob 匹配器只是没有优化。例如,请参阅这个 bug-bash 线程,其中 bash 维护者 Chet Ramey 说:

它不是一个正则表达式引擎,它是一个即时解释匹配器。

由于 bash 还包含一个正则表达式引擎(使用=~而不是==inside [[ ]]),因此可能没有太多动力去做任何事情。

在我的机器上,等效的 regexp ( ^(.*[[:print:]])?foobar$) 受到 locale-aware 的影响[[:print:]];出于某种原因,这并没有影响全局匹配器。设置 LANG=C 使正则表达式工作正常。

但是,对于这样大小的字符串,我会使用 grep。

于 2013-08-23T22:20:31.407 回答
3

正如其他人所指出的,您最好使用grep.

也就是说,如果你想坚持使用[[条件 - 结合 @konsolebox 和 @rici 的建议 - 你会得到:

[[ $(<foobar.txt)  =~ (^|[[:print:]])foobar$ ]]

编辑:更新正则表达式以符合 OP 的要求 - 谢谢,@rici。

一般来说,最好使用正则表达式进行字符串匹配(=~在这种情况下通过运算符),而不是 [globbing]模式(通过==运算符),其主要目的是匹配文件和文件夹名称。

于 2013-08-23T22:26:51.590 回答
1

仅仅因为你做了许多 bash 的分支(一个用于 subshel​​l,一个用于 cat 命令),而且,你在执行 cat 二进制文件时也会读取它。

[[ `cat foobar.txt` == *[[:print:]]foobar ]]

这种形式会更快:

[[ $(<foobar.txt) == *[[:print:]]foobar ]]

或者

IFS= read -r LINE < foobar.txt && [[ $LINE == *[[:print:]]foobar ]]

如果没有区别,那么模式匹配的速度可能与您使用的 Bash 版本有关。

于 2013-08-23T21:45:54.493 回答