awkの動的正規表現

Nov 22 2020

私は次のようなテキストファイルを持っています

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スクリプトを使用します(Windowsではcmdを使用して使用します)

#!/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出力から削除されていることがわかります。

私はそれが関係している疑いがある(...)正規表現は中にグループ分けとして採用されているmatch()最初のパラメータはREGEXあるとして渡すことで$0、両方ともで「動的正規表現*として扱われますoをawk話します

回答

1 EdMorton Nov 22 2020 at 23:36
$ 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)。