행을 행 그룹으로 변환

행을 행 그룹으로 변환

누군가 아래 변환 쉘 스크립트를 도와줄 수 있습니까?

소스 파일 파일 1: 예

EXCHANGE_ID     :  192,                       410,
EXCHANGE_DTTM   :  2015-06-11+02:18:40+0000,        2015-06-11+02:12:28+0000,
PART_NAME       :  MRT,                     LR04,
PART_TRANS_ID   :  123,                       JAS04,
M_NAME      :  FAILED,  FAILED,
M_DTTM      :  2015-06-11T02:18:40+0000      2015-06-11T02:12:28+0000

출력은 다음과 같습니다

EXCHANGE _ID    :  192
EXCHANGE_ DTTM  :  2015-06-11T02:18:40+0000
PART_NAME       :  MRT
PART_TRANS_ID   :  123
M_NAME          :  FAILED
M _DTTM         :  2015-06-11T02:18:40+0000

EXCHANGE _ID    :  410
EXCHANGE_DTTM   :  2015-06-11T02:12:28+0000
PART_NAME       :  LR04
PART_TRANS_ID   :  JAS04
M_NAME          :  FAILED
M_DTTM          :  2015-06-11T02:12:28+0000

이것이 내가 지금까지 시도한 것입니다:

awk '{ for (i = 1; i <= NF; i++) f[i] = f[i] " " $i ; if (NF > n) n = NF } END { for (i = 1; i <= n; i++) sub(/^ */, "", f[i]) ; for (i = 1; i <= n; i++) print f[i] } ' FAILED.csv > TGT_FAILED.out

하지만 이는 원하는 형식이 아닌 CSV 형식으로 내용을 인쇄할 뿐입니다. 다음은 위에서 원하는 출력이 아닌 실제 출력의 예입니다.

EXCHANGE_ID EXCHANGE_DTTM PART_NAME PART_TRANS_ID M_NAME M_DTTM
: : : : : :
192, 2015-06-11+02:18:40+0000, MRT, 123, FAILED, 2015-06-11T02:18:40+0000
410, 2015-06-11+02:12:28+0000, LR04, JAS04, FAILED, 2015-06-11T02:12:28+0000

답변1

어때요?

awk -F'[ \t,]+' '{a=a$1"\t"$2"\t"$3"\n"; b=b$1"\t"$2"\t"$4"\n"} END {print a; print b}' data.txt

여기서는 하나 이상의 공백, 탭 또는 쉼표를 필드 구분 기호로 간주합니다. 그런 다음 각 줄에 출력을 작성합니다. 마지막으로 결과를 인쇄합니다. 예를 들어 이것은 매우 지저분한 라이너입니다. 예를 들어 인쇄하기 전에 전체 파일을 읽어야 하므로 큰 파일의 경우 메모리를 차지하지만 작은 파일의 경우 트릭을 수행해야 합니다.

귀하의 입력에 따르면 다음과 같은 결과가 발생합니다.

EXCHANGE_ID :   192
EXCHANGE_DTTM   :   2015-06-11+02:18:40+0000
PART_NAME   :   MRT
PART_TRANS_ID   :   123
M_NAME  :   FAILED
M_DTTM  :   2015-06-11T02:18:40+0000

EXCHANGE_ID :   410
EXCHANGE_DTTM   :   2015-06-11+02:12:28+0000
PART_NAME   :   LR04
PART_TRANS_ID   :   JAS04
M_NAME  :   FAILED
M_DTTM  :   2015-06-11T02:12:28+0000

필드 간격을 적절하게 지정하려면 다음과 같이 호출에 sprintf를 추가할 수 있습니다.

awk -F'[ \t,]+' '{label=sprintf("'%-10s'",$1); a=a""label"\t"$2"  "$3"\n"; b=b""label"\t"$2"  "$4"\n"} END {print a; print b}' data.txt

이것은 더 예쁜 출력을 제공합니다.

EXCHANGE_ID     :  192
EXCHANGE_DTTM   :  2015-06-11+02:18:40+0000
PART_NAME       :  MRT
PART_TRANS_ID   :  123
M_NAME          :  FAILED
M_DTTM          :  2015-06-11T02:18:40+0000

EXCHANGE_ID     :  410
EXCHANGE_DTTM   :  2015-06-11+02:12:28+0000
PART_NAME       :  LR04
PART_TRANS_ID   :  JAS04
M_NAME          :  FAILED
M_DTTM          :  2015-06-11T02:12:28+0000

답변2

sed이것을 데이터에 적용하는 방법을 생각해 본 적이 없다면 다음을 보여드리겠습니다.

sed '    s/\([^, ]\{1,\}\),*/\1,/2                                                                                 
         s//\1/3;H;y/,/\n/;P;/^M_D.*/!d
         s///;x;s/[^, ]*, *//g
'        <<\IN
EXCHANGE_ID:  192,                       410,
EXCHANGE_DTTM:  2015-06-11+02:18:40+0000,        2015-06-11+02:12:28+0000,
PART_NAME:  MRT,                     LR04,
PART_TRANS_ID:  123,                       JAS04,
M_NAME:  FAILED,  FAILED,
M_DTTM:  2015-06-11T02:18:40+0000      2015-06-11T02:12:28+000
IN

따라서 첫 번째 단계에서는 P쉼표가 처음 나타나는 부분까지만 인쇄합니다. 모든 필드를 쉼표로 구분하면 더 간단해질 것입니다. 하지만 그렇지 않기 때문에 작업의 절반 정도가 제대로 작동하는지 확인하는 데 소비됩니다.

어쨌든 제목과 공백이 아닌 문자의 첫 번째 시퀀스만 인쇄합니다. 다음으로 현재 행의 복사본을 H이전 공간에 추가한 다음 d삭제합니다.~하지 않는 한일치합니다 ^M_D. 이 경우 x보존 및 패턴 공간을 변경한 다음 s///방금 저장한 각 줄에서 공백이 아닌 문자의 두 번째 시퀀스와 모든 후속 공백을 동시에 제거합니다.

결과는 표준 출력으로 인쇄됩니다.

EXCHANGE_ID:  192
EXCHANGE_DTTM:  2015-06-11+02:18:40+0000
PART_NAME:  MRT
PART_TRANS_ID:  123
M_NAME:  FAILED
M_DTTM:  2015-06-11T02:18:40+0000

EXCHANGE_ID:  410
EXCHANGE_DTTM:  2015-06-11+02:12:28+0000
PART_NAME:  LR04
PART_TRANS_ID:  JAS04
M_NAME:  FAILED
M_DTTM:  2015-06-11T02:12:28+000

답변3

입력 파일 처리그룹 16줄만요2 데이터열은 간단하지만 제한적이고 탐욕스러운 리소스 접근 방식으로 코딩 오버헤드를 최소화합니다.정렬6개 데이터 행을 모두 저장합니다.

f='src.txt'       # input fule
d=' +: +| +|, *'  # field delimiter regex
set {2,3}         # data columns - not label (which is column 1)
for c; do paste \
   <(gawk -F"$d" '1,6{print $1"\t:"}' "$f") \
   <(gawk -F"$d" '1,6{print $c}' c=$c "$f") |
     column -t; echo; done

다음 awk방법은 행당 필드 수에 관계없이 6개 행의 무한 반복 그룹을 처리합니다.

awk 'BEGIN{ FS=" +: +|, +|,| +"; OFS="\t"; maxw=length("EXCHANGE_DTTM") }
     /^EXCHANGE_ID/,/^M_DTTM/{ rn++
       if($NF=="") NF--
       for(fn=1;fn<=NF;fn++) cell[rn"."fn]=$fn
       if(rn==6){
         for(fn=2;fn<=NF;fn++) 
           for(rn=1;rn<=6;rn++)
             printf("%-"maxw"s : %s\n"(rn==6?"\n":""), cell[rn"."1], cell[rn"."fn]) 
         rn=0 }}' <"$f"

산출:

EXCHANGE_ID   : 192
EXCHANGE_DTTM : 2015-06-11+02:18:40+0000
PART_NAME     : MRT
PART_TRANS_ID : 123
M_NAME        : FAILED
M_DTTM        : 2015-06-11T02:18:40+0000

EXCHANGE_ID   : 410
EXCHANGE_DTTM : 2015-06-11+02:12:28+0000
PART_NAME     : LR04
PART_TRANS_ID : JAS04
M_NAME        : FAILED
M_DTTM        : 2015-06-11T02:12:28+0000

bash다음은 위 스크립트의 버전 입니다 . awk논리적 흐름은 동일합니다. 오류 검사와 빈 줄 건너뛰기를 추가했습니다.

set EXCHANGE_DTTM; maxw=${#1}; nl=0    # length of longest label; line number
set -f; declare -A cell; cm=" "; nf=0  # no-globbing; cells-array; cell-margin; number-of-fields 
while IFS= read -r line; do ((nl+=1))  # increment line number
  [[ $line =~ ^[[:blank:]]*$ ]] && continue            # skip blank/empty lines 
  [[ $line =~ ^EXCHANGE_ID\ * ]] && rn=1 || ((rn+=1))  # reset/increment record number
  IFS=" ,"; f=(${line/ : / }); IFS=; f=(${f[@]})       # split line into fields
  (( nf )) && (( nf!=${#f[@]} )) && { echo ERROR: field count is not consistent; exit 1; } || nf=${#f[@]} 
  for (( fn=0; fn<nf; fn++ ));do cell[$rn.$fn]="${f[$fn]}"; done  # build cells-array
  (( rn==6 )) && {
    [[ $line =~ ^M_DTTM\ .* ]] || { echo ERROR: unexpected label found - record $rn$'\n'"$line"; exit 2; }
    for (( fn=1; fn<nf; fn++ )) ;do
      for (( rn=1; rn<=6; rn++ )) ;do
        (( rn==6 )) && b=$"\n" || b=""
        printf "%-${maxw}s${cm}:${cm}%s\n$b" "${cell[$rn.0]}" "${cell[$rn.$fn]}"
        done; done; } done <"$f"

관련 정보