我想在 36 核机器上快速地 grep 10M 文件中的模式,我尝试过这个
find . -name '*.xml' -type f | xargs -P 20 grep "username" >> output
但我在两者之间得到了一些其他结果。
有没有更好的方法来做到这一点?
提前致谢。
答案1
鉴于您的数据位于非 RAIDed HDD 上,我怀疑您能否通过并行化获得更好的性能,瓶颈很可能是 I/O,而不是 CPU。
LC_ALL=C grep -rwF --include='*.xml' username . > /on/some/other/disk/output
可能接近您能达到的最佳水平。
要并行化,您需要这样做:
LC_ALL=C find . -name '*.xml' -type f -print0 |
LC_ALL=C xargs -r0P20 -n 1000 grep -HFw --line-buffered username > output
假设没有输出行(输入行 + 文件路径名)长于 4KiB,并注意所有 20 个并发 grep 的行最终将交错。
看:
了解详情。
答案2
我认为这是因为模式太笼统了。通常,命令行实用程序将错误打印到 stderr 或终端。它们不应该进入输出文件。
答案3
如果您以这种方式grep
pingxml
文件,那么您的搜索将返回包含搜索字符串的整行,如果文件xml
没有换行符,则返回整个文件内容。 10M 文件中相当多的“其他”。
xml
根据@Kusalananda 评论,强行使用withgrep
和解析器并不是一个好习惯,xml
例如xmllint
是一个更好的工具,但是,如果你坚持......
检查并阅读man
限制返回值的选项,并使用它定义您要查找的匹配的整个长度。grep
-o
regex
如果username
是一个属性
grep -o 'username="[^"]*"'
或更好
xmllint --xpath "//@username"
如果username
是一个节点那么类似
grep -o "username>[^<][^<]*"
或更好
xmllint --xpath "//username"
对于任一xmllint
查询,只需将查询包装起来string()
即可提取属性或节点文本。
xmllint --xpath "string(//username)"
xmllint --xpath "string(//@username)"