GAWK 在 FOR 中连接变量

GAWK concat variables in FOR

我当前的 GAWK 脚本获取短语文件,并创建正则表达式模式数组,然后用 \t 字符拆分每一行并循环每行的前 10 列,然后检查它是否至少包含模式数组中的一个短语, 如果是,它会跳过该行并且不会将其打印到文档中。

问题:

因为短语文件很大,它会产生大量的迭代并使脚本非常慢。

(700 patterns x 10 columns (separated by tab \t)) x 1000 of rows.

解决方案:

为了提高速度,我想连接前 10 列,并检查整个字符串是否至少包含一个模式。我不知道如何在 FOR 循环中连接行。

工作示例:

gawk 'BEGIN{
FS=" *\t *";
IGNORECASE=1;

while(getline a < "'$phpath'") PATS["^.*"a".*$"]
}

{
    ok=1;
    for(i=1;i<=10;i++){
        for(p in PATS){
            if($i ~ p){
            ok=0
            }
        }
    }

} 
ok {print}' "$f" > "$newPath$filename" 

我的尝试:

gawk 'BEGIN{
    FS=" *\t *";
    IGNORECASE=1;

    while(getline a < "'$phpath'") PATS["^.*"a".*$"]
    }

    {
        phrase="";
        space=" ";
        ok=1;

        for(i=1;i<=10;i++){
            phrase = $space $phrase $i
        }

        for(p in PATS){
            if($phrase ~ p){
                ok=0
            }
        }

    } ok {print}' "$f" > "$newPath$filename"

在 awk 中,您使用 $ 就像 取消引用运算符 ,其中 $x 表示 "give me the value of the column whose number is in variable x"

要将前 10 列放入字符串中:

    for (i=1; i<=10; i++) {
        # not this => phrase = $space $phrase $i
        phrase = space phrase $i
    }

    for (p in PATS) {
        if (phrase ~ p) {   # <= no $
            ok = 0
            break           # no match, so break the loop early
        }
    }

awk 使用像 C 那样的变量,而不像 shell 或 perl


您也可以试试这个:

gawk -v patternfile="$phpath" '
    BEGIN {
        FS = " *\t *"
        IGNORECASE = 1
        while ((getline a < patternfile) > 0)
            PATS["^.*"a".*$"]
    }
    {
        line = [=12=]
        NF = 10         # this truncates the current record to 10 fields
        ok = 1
        for (p in PATS) 
            if ([=12=] ~ p) {
                ok = 0
                break
            }
        if (ok) 
            print line
    }
' "$f" > "$newPath$filename"

这不是您问题的答案,但可能是您的问题。

我了解到您的问题与性能有关。

据我了解,您遇到的主要问题之一是您使用的是 RegEx。让我解释一下我的观点。在 AWK 中,当你使用像这样的正则表达式时:/MyRegExp/,你使用的是正则表达式的编译版本,所以每次你需要检查匹配时,你只检查它,但是当你像这样使用正则表达式时:"MyRegExp",每次你想检查一个字符串是否匹配时都会编译它。

你真的在检查 RegEx 吗?也许你不是,函数 'index' 对你来说已经足够好了。

您为什么不尝试构建一个脚本并 运行 它呢?而不是根据加载的模式检查第二个文件中的每一行,而是创建如下脚本:

/pattern1/{
    print
    next
}
/pattern2/{
    print
    next
}
/pattern3/{
    print
    next
}
...
...

然后 运行 它与第二个文件。总之,希望对大家有所帮助。

while(getline a < "'$phpath'") PATS["^.*"a".*$"]

RE ^.*"a".*$ 等同于 a。您可以直接使用 | 声明 OR 条件,而不是遍历模式。

如果您的输入文件是

every
good
boy
does
fine

你的 RE 变成了 every|good|boy|does|fine 而你的代码缩减为

[=12=] ~ pattern { 
    for (i=1; i<=10; i++) {
        if( $i ~ pattern ) { 
           print "$f" > "$newPath$filename" # what's $f?  
           break
        }
    }
}

即先整行扫描。如果找到某些内容,则遍历前 10 列。我敢打赌这比无条件地迭代它们要快。