Regex 提高Shell脚本性能
此shell脚本用于从Regex 提高Shell脚本性能,regex,performance,unix,shell,grep,Regex,Performance,Unix,Shell,Grep,此shell脚本用于从$2中提取一行数据,如果它包含模式$line $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具有短数据行(80到
$2
中提取一行数据,如果它包含模式$line
$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
具有短数据行(<100个字符),包含约50k行(约1-1.5MB)
文件$2
有稍长的文本行(>80到<200),有超过200行(约200MB)
它运行的台式机有大量的RAM(6G)和2-4核的Xenon处理器
由于目前需要1-2小时才能完全运行(并输出到另一个文件),是否有任何快速修复方法来提高性能
注意:我愿意接受所有建议,但我们无法重新编写整个系统等。此外,数据来自第三方,并且容易出现随机格式。如果$1是一个文件,请不要使用“cat | grep”。相反,直接将文件传递给grep。应该像
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" $1
此外,您可能需要调整正则表达式。您至少应该在电子邮件地址中使用下划线(“389;”),因此
grep -i -o -E "[A-Z0-9._-]+@[A-Z0-9.-]+" $1
如果$1是一个文件,不要使用“cat | grep”。相反,直接将文件传递给grep。应该像
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" $1
此外,您可能需要调整正则表达式。您至少应该在电子邮件地址中使用下划线(“389;”),因此
grep -i -o -E "[A-Z0-9._-]+@[A-Z0-9.-]+" $1
快速建议:
cat X | grep Y
更改为grep Y X
grep
输出,因为它是通过管道传输而不是使用反勾号生成的。使用反勾号需要先完成第一个grep
,然后才能开始第二个grep
$2
。它很大。您可以保存所有模式,然后对文件执行单个grepsed
grep
:
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\1/g' > patterns
grep -f patterns "$2"
最后,使用一些bash
fancity(参见manbash
→ 进程替换)我们可以丢弃临时文件,并在一个长行中执行此操作:
grep -f <(grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\b/g') "$2"
一次可以处理100个图案。它一次能做的越多,它就越少通过你的第二个文件。快速建议:
cat X | grep Y
更改为grep Y X
grep
输出,因为它是通过管道传输而不是使用反勾号生成的。使用反勾号需要先完成第一个grep
,然后才能开始第二个grep
$2
。它很大。您可以保存所有模式,然后对文件执行单个grepsed
grep
:
grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\1/g' > patterns
grep -f patterns "$2"
最后,使用一些bash
fancity(参见manbash
→ 进程替换)我们可以丢弃临时文件,并在一个长行中执行此操作:
grep -f <(grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+" "$1" | sed -E 's/^|$/\\b/g') "$2"
一次可以处理100个图案。它一次可以执行的操作越多,它就越少地传递第二个文件。问题在于您正在传输过多的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
awk'FNR==NR{
#从文件1获取所有电子邮件地址
对于(i=1;i而言,问题在于您正在传输过多的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
awk'FNR==NR{
#从文件1获取所有电子邮件地址
对于(i=1;i我将取消循环,因为将200万行文件灰显50k次可能非常昂贵;)
让你可以把这个循环拿出来
首先使用外部grep命令创建一个包含所有电子邮件地址的文件。
然后将其作为一个模式文件,使用grep-f进行第二次grep,我将执行循环,因为将一个200万行文件进行50k次的grep可能非常昂贵;)
让你可以把这个循环拿出来
首先使用外部grep命令创建一个包含所有电子邮件地址的文件。
然后将其用作模式文件,通过使用grep-f进行第二次grep,正如John Kugelman已经回答的那样,通过管道而不是使用反勾号来处理grep
输出。如果使用反勾号,将首先运行反勾号中的整个表达式,然后使用来自的输出运行外部表达式背景符号作为参数
首先,这将比必要的慢很多,因为管道将允许两个程序同时运行(如果它们都是CPU密集型的,并且您有多个CPU,这将非常好)。然而,这还有另一个非常重要的方面,线路
for line in `cat "$1" | grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+"`
可能会对外壳产生渴望。大多数外壳(至少据我所知)限制命令行的长度,或者至少限制命令的参数,我认为这也可能成为for
循环的问题。正如John Kugelman已经回答的那样,通过管道处理grep
输出,而不是使用backticks。如果使用backticks,则backticks中的整个表达式将首先运行,然后外部表达式将以backticks的输出作为参数运行
首先,这将比必要的慢很多,因为管道将允许两个程序同时运行(如果它们都是CPU密集型的,并且您有多个CPU,这将非常好)。然而,这还有另一个非常重要的方面,线路
for line in `cat "$1" | grep -i -o -E "[A-Z0-9.-]+@[A-Z0-9.-]+"`
可能会对shell处理变得太长。大多数shell(至少据我所知)限制命令行的长度,或者至少限制命令的参数,我认为这也可能成为for
循环的问题。不要这样做