我有一个包含 10000 个单词的Words.txt(一个单词到一行)。我有 5,000 个文档。我想查看哪些文档包含哪些单词(单词周围有正则表达式模式)。我有一个 script.sh 来 grep 文档并输出命中。我想(1)将我的输入文件分割成更小的文件(2)将每个文件作为参数提供给 script.sh 并(3)并行运行所有这些。
我的尝试基于教程遇到错误
$parallel ./script.sh ::: split words.txt # ./script.sh: line 22: split: No such file or directory
我的 script.sh 看起来像这样
#!/usr/bin/env bash
line 1 while read line
line 2 do
some stuff
line 22 done < $1
我想我可以通过启动 grep 命令的目录中的文件将 split 输出到目录循环 - 但如何优雅而简洁地做到这一点(使用并行)?
答案1
您可能不需要临时文件,因为您是从 STDIN 读取的。所以确实没有理由使用split
。使用以下命令删除文件--pipe
:
cat words | parallel --pipe -L 1000 -N1 ./script.sh
如果它确实只是您想要的 grep:
find dir-with-5000-files -type f | parallel -X grep -f words.txt
如果words.txt
太大而无法容纳在内存中,您可以将其拆分:
find dir-with-5000-files -type f | parallel -X "cat words.txt | parallel --pipe grep -f -"
GNU Parallel 的手册页介绍了如何最有效地 grep n 行 m 正则表达式:https://www.gnu.org/software/parallel/parallel_examples.html#example-grepping-n-lines-for-m-regular-expressions
grep 大量正则表达式的大文件的最简单解决方案是:
grep -f regexps.txt bigfile
或者如果正则表达式是固定字符串:
grep -F -f regexps.txt bigfile
有 2 个限制因素:CPU 和磁盘 I/O。 CPU 很容易测量:如果 grep 占用 >90% CPU(例如,运行 top 时),那么 CPU 是一个限制因素,并行化将加快这一速度。如果不是,则磁盘 I/O 是限制因素,并且根据磁盘系统,并行化可能会更快或更慢。唯一确定的方法就是测量。
如果 CPU 是限制因素,则应在正则表达式上进行并行化:
cat regexp.txt | parallel --pipe -L1000 --round-robin grep -f - bigfile
这将为每个 CPU 启动一个 grep 并为每个 CPU 读取一次大文件,但由于这是并行完成的,除了第一个读取之外的所有读取都将缓存在 RAM 中。根据 regexp.txt 的大小,使用 --block 10m 而不是 -L1000 可能会更快。如果 regexp.txt 太大而无法放入 RAM,请删除 --round-robin 并调整 -L1000。这将导致bigfile被读取更多次。
一些存储系统在并行读取多个块时性能更好。对于某些 RAID 系统和某些网络文件系统来说确实如此。并行读取大文件:
parallel --pipepart --block 100M -a bigfile grep -f regexp.txt
这会将 bigfile 分割成 100MB 的块,并对每个块运行 grep。要并行读取 bigfile 和 regexp.txt,请使用 --fifo 将两者结合起来:
parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \
\| parallel --pipe -L1000 --round-robin grep -f - {}
答案2
您可以使用该split
工具:
split -l 1000 words.txt words-
将把你的words.txt
文件分割成多个文件,每个文件的命名不超过 1000 行
words-aa
words-ab
words-ac
...
words-ba
words-bb
...
如果省略前缀(words-
在上面的示例中),split
则用作x
默认前缀。
要使用生成的文件,parallel
您可以使用 glob:
split -l 1000 words.txt words-
parallel ./script.sh ::: words-[a-z][a-z]