行を行グループに変換

行を行グループに変換

誰かが以下の変換シェルスクリプトを助けることができますか?

ソースファイルファイル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

ここでは、1 つ以上のスペース、タブ、またはコンマをフィールド区切り文字と見なします。次に、各行に出力を作成します。最後に結果を印刷します。たとえば、これは非常に汚れたライナーです。たとえば、印刷する前にファイル全体を読み取る必要があるため、大きなファイルの場合はメモリを消費しますが、小さいファイルの場合はトリックを実行する必要があります。

あなたの入力によると、次のような結果が発生します。

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///の2番目のシーケンスとすべての後続のスペースを同時に削除します。

結果は標準出力として印刷されます。

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方法は、1行あたりのフィールド数に関係なく、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"

関連情報