如果$2
包含模式$line
,则此shell脚本用于从$line
中提取一行数据。
[A-Z0-9.-]+@[A-Z0-9.-]+
使用正则表达式$1
(简单的电子邮件匹配)构建,形成文件#! /bin/sh
clear
for line in `cat "$1" | grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+"`
do
echo `cat "$2" | grep -m 1 "\b$line\b"`
done
中的行。
$1
文件$2
包含短行数据(< 100 chars)并包含约。 50k行(约1-1.5 MB)。
文件{{1}} 的文字行数稍长(> 80到<200),并且有2M +行(约200MB)。
运行的台式机有足够的RAM(6 Gig)和1-2核的Xenon处理器。
是否有任何快速修复可以提高性能,因为目前完全运行需要1-2个小时(并输出到另一个文件)。
注意:我对所有建议持开放态度,但我们不能复杂地重写整个系统等。此外,数据来自第三方,并且易于随机格式化。< / em>的
答案 0 :(得分:7)
快速建议:
避免使用useless use of cat
并将cat X | grep Y
更改为grep Y X
。
您可以处理grep
输出,因为它是通过管道而不是使用反引号生成的。使用反引号需要先完成grep
才能开始第二个grep
。
因此:
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | while read line; do
grep -m 1 "\b$line\b" "$2"
done
下一步:
$2
。很大。您可以保存所有模式,然后对文件执行单个grep。sed
。不再重复grep
:
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\1/g' > patterns
grep -f patterns "$2"
最后,使用一些bash
幻想(参见man bash
→流程替换),我们可以抛弃临时文件,并在一个长行中执行此操作:
grep -f <(grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\b/g') "$2"
除非你有很多模式grep -f
内存和barf耗尽,否则这很好。如果发生这种情况,您需要批量运行它。讨厌,但可行:
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\1/g' > patterns
while [ -s patterns ]; do
grep -f <(head -n 100 patterns) "$2"
sed -e '1,100d' -i patterns
done
这将一次处理100个模式。它可以立即做的越少,你的第二个文件就越少。
答案 1 :(得分:3)
问题是你管道太多shell命令,以及不必要地使用cat。
使用awk
的一种可能的解决方案awk 'FNR==NR{
# get all email address from file1
for(i=1;i<=NF;i++){
if ( $i ~ /[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+/){
email[$i]
}
}
next
}
{
for(i in email) {
if ($0 ~ i) {
print
}
}
}' file1 file2
答案 2 :(得分:2)
如果$ 1是文件,请不要使用“cat | grep”。相反,将文件直接传递给grep。应该看起来像
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" $1
此外,您可能需要调整正则表达式。您至少应该期望电子邮件地址中的下划线(“_”),所以
grep -i -o -E "[A-Z0-9._-]+@[A-Z0-9.-]+" $1
答案 3 :(得分:2)
我会把循环取出来,因为花费200万行文件50k次可能相当昂贵;)
允许你取消循环 首先使用外部grep命令创建所有电子邮件地址的文件。 然后使用它作为模式文件,使用grep -f
来执行辅助grep答案 4 :(得分:1)
正如John Kugelman已经回答的那样,通过管道而不是使用反引号来处理grep
输出。如果你使用反引号,则首先运行反引号中的整个表达式,然后使用反引号的输出作为参数运行外部表达式。
首先,这将比必要的慢得多,因为管道将允许两个程序同时运行(如果它们都是CPU密集型且你有多个CPU,这真的很好)。然而,还有另一个非常重要的方面,即行
for line in `cat "$1" | grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+"`
可能会变得很长时间来处理shell。大多数shell(据我所知)限制命令行的长度,或者至少是命令的参数,我认为这也可能成为for
循环的问题。