grep 跨大型文件集的模式,无需 GNU 并行

grep 跨大型文件集的模式,无需 GNU 并行

我想在 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

如果您以这种方式greppingxml文件,那么您的搜索将返回包含搜索字符串的整行,如果文件xml没有换行符,则返回整个文件内容。 10M 文件中相当多的“其他”。

xml根据@Kusalananda 评论,强行使用withgrep和解析器并不是一个好习惯,xml例如xmllint是一个更好的工具,但是,如果你坚持......

检查并阅读man限制返回值的选项,并使用它定义您要查找的匹配的整个长度。grep-oregex

如果username是一个属性

grep -o 'username="[^"]*"'

或更好

xmllint --xpath "//@username"

如果username是一个节点那么类似

grep -o "username>[^<][^<]*"

或更好

xmllint --xpath "//username"

对于任一xmllint查询,只需将查询包装起来string()即可提取属性或节点文本。

xmllint --xpath "string(//username)"
xmllint --xpath "string(//@username)"

相关内容