首页 > 解决方案 > awk 中的动态正则表达式

问题描述

我有像这样的文本文件

1.txt

AA;00000;
BB;11111;
GG;22222;

2.txt

KK;WW;55555;11111;
KK;FF;ZZ;11111;
KK;RR;YY;11111;

我生成这个3.txt输出

AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY
GG;22222;

使用这个 .awk 脚本(我在带有 cmd 的 Windows 中使用它)

#!/usr/bin/awk -f 

NR != FNR {
    exit
}
{
    printf "%s", $0
}
/^BB/ {
    o = ""
    while (getline tmp < ARGV[2]) {
        n = split (tmp,arr,";")
        for (i=1; i<=n; i++)
            if(!match($0,arr[i]) && !match(o,arr[i]))
                o=o arr[i]";"
    }
    printf "%s", o
}
{
    print ""
}

用法是awk -f script.awk 1.txt 2.txt

似乎还可以,但考虑一下这种情况

1.txt

AA;BB;

2.txt

CC;DD;BB;AA;

现在以这种方式替换

AA替换d(2)
BB为 替换http://a.o/f/i.p?t=1
CC为 替换Link
DDA_x-y.7z

脚本无法生成3.txt

AA;BB;CC;DD;

或者,使用替换文本无法生成此 3.txt 文本输出

   d(2);http://a.o/f/i.p?t=1;Link;A_x-y.7z;

您可以看到像AA,这样BB 的重复字段已从 3.txt 输出中删除,因为脚本以这种方式工作。

我怀疑这与(...)被视为 REGEX 分组有关,match()因为第一个参数是 REGEX 并且通过传递and o 两者都$0将被视为“动态正则表达式*”awk

标签: bashawk

解决方案


$ cat tst.awk
BEGIN { FS=OFS=";" }
{ key = $(NF-1) }
NR == FNR {
    for (i=1; i<(NF-1); i++) {
        if ( !seen[key,$i]++ ) {
            map[key] = (key in map ? map[key] OFS : "") $i
        }
    }
    next
}
{ print $0 map[key] }

$ awk -f tst.awk 2.txt 1.txt
AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY
GG;22222;

以上只是在数组索引的哈希查找中使用文字字符串,因此它不关心您输入中的字符。如果您希望您的输入被视为文字字符串,则不要在其上使用正则表达式函数或运算符(例如match(), ) ~sub()只需使用字符串函数/运算符(例如index(), ==, substr(), in)。


推荐阅读