我有一个文本文件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 ]]
此 即时。但这只是上面的第二种选择,没有第一种选择。
那为什么这么久?
答案 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版本有关。