スクリプトでこのエラーが発生するのはなぜですか?awk:script.awk:19:「構文エラー

Nov 22 2020

私は2つのテキストファイルを持っています

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;KK;FF;ZZ;KK;RR;YY;
GG;22222;

重複するフィールドを削除した後、これが必要です

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

簡単に言うと、;(FS = ";")で区切られた2つのファイルで$n、ファイル1のフィールド$mがファイル2の任意の場所に存在し、m、nが1でない場合は、に追加$0(file2,m)$0(file1,n)ます。重複するフィールドは避ける必要があります。

解決策をスケッチしてみます

awk -f script.awk 2.txt 1.txt

スクリプトは次のとおりです。

BEGIN {
    FS=";"
    OFS=";"
}

NR==FNR {
    allRecordsFile2[i++] = $0; next; } { for(r in allRecordsFile2) { split(allRecordsFile2[r],";",array) for(f in array) { for($2 through $n of file1 currently processed) { if $n == f --> $0 = $0";"allRecordsFile2[r]
             }
         }
    }

    ## cleanup duplicates

    print $0
}

私はまだクリーンアップの重複を打ち出す必要がありますが、おそらくこれは、重複を追跡するためにカウント配列で分割$0";"て使用することで実行できます。

しかし、このスクリプトを実行した後、構文エラーが返されます

C:\Program Files (x86)\GnuWin32\bin>awk -f script.awk file2.txt file1.txt

awk: script.awk:17: for($2 through $n of filei currently processed)
awk: script.awk:17: “ syntax error
awk: script.awk:19: if $n == f --> $0 = $0";"allRecordsFile2[r] awk: script.awk:19: “ syntax error awk: script.awk:19: if $n == f --> $0 = $0";"allRecordsFile2[r]
awk: script.awk:19: “ syntax error
errcount:3

回答

2 DavidC.Rankin Nov 22 2020 at 11:56

順次読み取りを試みてFNR/NRに基づいて制御するのではなく、を使用getlineして読み取り2.txtと分割を';'行い、o各行の一意のコンポーネントを連結する出力文字列(以下)を作成してみませんか?次のようなことができます。

awk '{
        printf "%s", $0 } /^BB/ { o = "" while (getline tmp < "2.txt") { 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 ""
    }
' 1.txt

使用例/出力

1.txtおよび2.txt1.txt再度名前を間違えた)のサンプルデータを使用すると、次のようになります。

$ awk '{ > printf "%s", $0
>     }
>     /^BB/ {
>         o = ""
>         while (getline tmp < "2.txt") {
>             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 ""
>     }
> ' 1.txt
AA;00000;
BB;11111;KK;WW;55555;FF;ZZ;RR;YY;
GG;22222;

それはあなたが望むもののように見えます。


2つのファイル名を引数として取るスクリプトとして

Windowsは、を使用して同じ規則に従う必要がありますARGVawkスクリプト内で実行する場合は、ルールを一重引用符で囲まないように注意してください。

#!/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 ""
}

注:/usr/bin/awkインタプリタをお持ちのものに変更する必要があります)

使用法は、例えば ./test.awk 1.txt 2.txt

それが役立つかどうか教えてください。

2 glennjackman Nov 22 2020 at 13:35

連想配列のキーを使用すると、重複するアイテムを処理するのに便利です。これには、多次元配列用のGNUawkが必要です

BEGIN { FS = OFS = ";" }
NR == FNR {
    for (i=1; i<NF-1; i++)
        f2[$(NF-1)][$i] = ++n
    next
}
FNR == 1 {
    # this joins all the 2nd-level indices
    # the order of them is undefined.
    for (x in f2) {
        s = ""
        for (y in f2[x])
            s = s y OFS
        a[x] = s
    }
}
$(NF - 1) in a { $NF = a[$(NF-1)] }
1

その後

gawk -f script.awk {2,1}.txt

を生成します

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

URLで「機能しない」という証拠がもっと必要です。

$ cat 1.txt
AA;http://a.o/f/i.p?t=00000;
BB;http://a.o/f/i.p?t=11111;
GG;http://a.o/f/i.p?t=22222;

$ cat 2.txt KK;WW;55555;http://a.o/f/i.p?t=11111; KK;FF;ZZ;http://a.o/f/i.p?t=11111; KK;RR;YY;http://a.o/f/i.p?t=11111; $ gawk -f script.awk {2,1}.txt
AA;http://a.o/f/i.p?t=00000;
BB;http://a.o/f/i.p?t=11111;55555;WW;KK;RR;YY;FF;ZZ;
GG;http://a.o/f/i.p?t=22222;