假设我有一个模式所在的文件,例如的 patterns.txt 即可。而且我知道所有模式只会在另一个文件 patterns_copy.txt 中匹配一次,在这种情况下,简单起见只是 patterns.txt 的副本。
如果我跑
grep -m 1 --file=patterns.txt patterns_copy.txt > output.txt
我只得到一行。我想是的,因为一旦两个文件的第一行匹配, m 标志就会停止整个匹配过程。
我想要实现的是让 patterns.txt 中的每个模式只匹配一次,然后让grep移动到下一个模式。
我如何实现这一目标?
感谢。
答案 0 :(得分:2)
更新了答案
我现在有机会将我在考虑awk
的内容整合到GNU Parallel
概念中。
我使用/usr/share/dict/words
作为我的patterns
文件,其中有235,000行。在另一个答案中使用BenjaminW的代码,花了141分钟,而这段代码却缩短到11分钟。
这里的区别在于没有临时文件,awk
一旦找到它正在寻找的所有8个东西就可以停止...
#!/bin/bash
# Create a bash function that GNU Parallel can call to search for 8 things at once
doit() {
# echo Job: $9
# In following awk script, read "p1s" as a flag meaning "p1 has been seen"
awk -v p1="$1" -v p2="$2" -v p3="$3" -v p4="$4" -v p5="$5" -v p6="$6" -v p7="$7" -v p8="$8" '
$0 ~ p1 && !p1s {print; p1s++;}
$0 ~ p2 && !p2s {print; p2s++;}
$0 ~ p3 && !p3s {print; p3s++;}
$0 ~ p4 && !p4s {print; p4s++;}
$0 ~ p5 && !p5s {print; p5s++;}
$0 ~ p6 && !p6s {print; p6s++;}
$0 ~ p7 && !p7s {print; p7s++;}
$0 ~ p8 && !p8s {print; p8s++;}
{if(p1s+p2s+p3s+p4s+p5s+p6s+p7s+p8s==8)exit}
' patterns.txt
}
export -f doit
# Next line effectively uses 8 cores at a time to each search for 8 items
parallel -N8 doit {1} {2} {3} {4} {5} {6} {7} {8} {#} < patterns.txt
只是为了好玩,这就是它对我的CPU的作用 - 蓝色意味着最大化,看看你是否可以在绿色CPU历史中看到作业的开始位置!
其他想法
以上好处是输入文件排序相对较好,因此值得一次查找8件事,因为它们很可能在输入文件中彼此接近,因此我可以避免相关的开销为每个寻求的术语创建一个过程。但是,如果您的数据排序不好,这可能意味着您需要花费大量时间查看文件,而不是查找下一个或其他6个项目所需的时间。在这种情况下,你可能会更好:
parallel grep -m1 "{}" patterns.txt < patterns.txt
原始答案
看了一下文件的大小,我现在认为awk
可能不是可行的方法,但GNU Parallel
可能就是这样。我尝试了两种方法并行化问题。
首先,我通过输入文件一次搜索8个项目,这样我就可以使用grep
参数搜索第二组-m 1
。
其次,由于我有CPU核心,我并行执行这些“8-at-a-time” grep
的多个。
我使用GNU并行作业号{#}
作为唯一的临时文件名,并且一次只创建16个(或者多个CPU核心)临时文件。临时文件的前缀为ss
(用于子搜索),因此在测试时可以轻松地调用它们。
加速似乎是我机器上的4倍。我使用/usr/share/dict/words
作为我的测试文件。
#!/bin/bash
# Create a bash function that GNU Parallel can call to search for 8 things at once
doit() {
# echo Job: $9
# Make a temp filename using GNU Parallel's job number which is $9 here
TEMP=ss-${9}.txt
grep -E "$1|$2|$3|$4|$5|$6|$7|$8" patterns.txt > $TEMP
for i in $1 $2 $3 $4 $5 $6 $7 $8; do
grep -m1 "$i" $TEMP
done
rm $TEMP
}
export -f doit
# Next line effectively uses 8 cores at a time to each search for 8 items
parallel -N8 doit {1} {2} {3} {4} {5} {6} {7} {8} {#} < patterns.txt
答案 1 :(得分:1)
你可以像这样循环你的模式(假设你正在使用Bash):
while read -r line; do
grep -m 1 "$line" patterns_copy.txt
done < patterns.txt > output.txt
或者,在一行中:
while read -r line; do grep -m 1 "$line" patterns_copy.txt; done < patterns.txt > output.txt
对于并行处理,您可以将进程作为后台作业启动:
while read -r line; do
grep -m 1 "$line" patterns_copy.txt &
read -r line && grep -m 1 "$line" patterns_copy.txt &
# Repeat the previous line as desired
wait # Wait for greps of this loop to finish
done < patterns.txt > output.txt
这并不是很优雅,因为每个循环都会等待最慢的grep完成,但仍然应该比每个循环只有一个grep更快。