
|
各行には、可変数の列/フィールドがあるパイプで区切られたファイルがあります。最初の 2 つのフィールドと最後の 2 つのフィールドのみが常に存在し、間には最大 10 個までの多様な (偶数) フィールド数があるため、行には合計最大 14 個のフィールドがあります (2 + 0 .. .10 + 2)。
目的は、「不足している」フィールドを置き換え、ファイルを行ごとに固定数の列を持つファイルに変換することです。
C_A
「変数」フィールドの特徴は、常に...形式の「インデックスキー」C_E
と値で構成されることです。
入力例:
10|100|C_A|val_18|C_D|val_20|50|60
40|200|C_A|val_5|C_B|val_10|C_C|val_30|C_D|val_90|C_E|val_83|40|45
80|100|C_E|val_90|50|60
予想される結果は次のとおりです。
10|100|C_A|val_18|||||C_D|val_20|||50|60
40|200|C_A|val_5|C_B|val_10|C_C|val_30|C_D|val_90|C_E|val_83|40|45
80|100|||||||||C_E|val_90|50|60
答え1
GNU awk
名前をフィールドインデックスにマッピングすることでこの問題を解決できます。
- C_A => $3
- C_B => $5 ...など。
$ awk '
BEGIN {
OFS = FS = "|"
n = split("A-B-C-D-E", x, "-")
for (i=1; i<=n; ++i) h["C_" x[i]] = 2*(i-1) + 3
}
{
# record which out of
# ca/cb/.../ce present
for (i=3; i<NF-2; i+=2) seen[$i] = $(i+1)
# store fields in preparation
# for re-filling them based on seen
nf = split($0, f, FS); $0=""
# fill up the first two..easy does it
$(1) = f[1]
$(2) = f[2]
# recall which fields c_?
# were seen then fill up
# corresponding field and field value
for (var in h) {
i = h[var]
if (var in seen) {
$(i) = var
$(i+1) = seen[var]
} else { $(i) = $(i+1) = ""}
}
# append the last two fields
$(NF+1) = f[nf-1]
$(NF+1) = f[nf]
# above line **NOT** a typo
# clear out the array seen
# for the next iteration
split("", seen, ".")
}1
' file
結果:
10|100|C_A|val_18|||||C_D|val_20|||50|60
40|200|C_A|val_5|C_B|val_10|C_C|val_30|C_D|val_90|C_E|val_83|40|45
80|100|||||||||C_E|val_90|50|60
答え2
変数フィールドを配列として読み込み、配列を印刷し、行に使用されていないときに空の文字列を生成します(忘れないでください-F '|'
)。
BEGIN{
# initialize expected keys for file (value 1 not used)
all_keys["C_A"]=1;
all_keys["C_B"]=1;
all_keys["C_C"]=1;
all_keys["C_D"]=1;
all_keys["C_E"]=1;
}
{
# fill arrays for line
for(i=3;i<NF-1;i+=2) {
key[$i]=$i;
value[$i]=$i+1;
}
# first two fields
printf $1"|"$2"|";
# all variable key/value pairs, occurring on line or not
for (k in all_keys) {
printf key[k]"|"value[k]"|";
}
# last two fields
print $NF-1"|"$NF;
# delete arrays so we don't carry over values into the next line
delete key;
delete value;
}