为什么Bash模式匹配?(* [[:class:]])foobar缓慢?

时间:2013-08-23 21:40:14

标签: regex bash

我有一个文本文件foobar.txt,大约10KB,不是很长。然而,在高性能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 ]]

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

那为什么这么久?

3 个答案:

答案 0 :(得分:6)

bash中的glob匹配器没有进行优化。例如,参见this bug-bash thread,其中bash维护者Chet Ramey说:

  

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

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

在我的机器上,等效的正则表达式(^(.*[[:print:]])?foobar$)受到区域设置感知[[:print:]]的影响很大;由于某种原因,这不会影响glob匹配器。设置LANG = C使正则表达式正常工作。

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

答案 1 :(得分:3)

正如其他人所说,你最好使用grep

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

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

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

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

答案 2 :(得分:1)

只是因为你做了许多bash的分支(一个用于子shell,一个用于cat命令),而且,当你执行它时,你也会读取cat二进制文件。

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

这种形式会更快:

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

或者

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

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