Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 提高Shell脚本性能_Regex_Performance_Unix_Shell_Grep - Fatal编程技术网

Regex 提高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到

此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
具有短数据行(<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
    。它很大。您可以保存所有模式,然后对文件执行单个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
    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
    。它很大。您可以保存所有模式,然后对文件执行单个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
    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
    循环的问题。

    不要这样做