分割文件,将每个部分作为参数传递给脚本,并行运行每个脚本

分割文件,将每个部分作为参数传递给脚本,并行运行每个脚本

我有一个包含 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]

相关内容