가변 개수의 열이 있는 파이프로 구분된 파일을 구문 분석하고 누락된 열을 교체하여 고정된 개수의 열로 변환

가변 개수의 열이 있는 파이프로 구분된 파일을 구문 분석하고 누락된 열을 교체하여 고정된 개수의 열로 변환

|각 행에 가변 개수의 열/필드가 있을 수 있는 파이프로 구분된( ) 파일이 있습니다 . 처음 두 필드와 마지막 두 필드만 항상 존재하며, 사이에는 최대 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;
}

관련 정보