Convertendo linhas para grupos de linhas

3

Alguém pode me ajudar com o script de conversão abaixo?

Arquivo de origem 1: por exemplo

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

OutPut como:

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

Veja o que tentei até agora:

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

mas isso apenas imprime um CSV em vez do formato desejado. Aqui está um exemplo da saída real, em oposição à saída desejada acima:

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
    
por arsh 24.06.2015 / 17:03

3 respostas

0

Que tal:

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

Aqui, tratamos um ou mais espaços, tabulações ou vírgulas como um separador de campos. Então, em cada linha, construímos a saída. Finalmente, imprimimos os resultados. Este é um forro bastante sujo; por exemplo, ele tem que ler o arquivo inteiro antes de imprimir qualquer coisa, então, para arquivos grandes, ele ficará ruim na memória, mas para arquivos pequenos ele deve funcionar.

Da sua entrada, isso deve resultar em:

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

Se você quiser que os campos sejam bem espaçados, você pode adicionar o sprintf à chamada assim:

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

Isto dá a saída mais bonita de:

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
    
por 24.06.2015 / 18:31
0

Se você ainda não considerou como o sed pode ser aplicado aos seus dados, permita-me demonstrar:

sed '    s/\([^, ]\{1,\}\),*/,/2                                                                                 
         s///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

Então, o primeiro passo é que nós P rint apenas até a primeira vírgula - e isso seria muito mais simples ainda se todos os campos fossem delimitados por vírgulas. Mas eles não são, e assim cerca de metade do trabalho é gasto garantindo que eles são.

De qualquer forma, imprimimos apenas o cabeçalho e a primeira seqüência seguinte de caracteres não espaciais. Em seguida, anexamos uma cópia da linha atual ao H old space e, em seguida, d elete it - a menos que corresponda a ^M_D . Nesse caso, nós e x alteramos os espaços hold e pattern, então, com uma única s/// ubstitution, removemos simultaneamente a segunda seqüência de caracteres não espacial e todos os espaços seguintes de cada linha que acabamos de salvar.

O resultado é impresso no stdout:

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
    
por 26.06.2015 / 07:52
0

Para lidar com um arquivo de entrada com apenas 1 grupo de 6 linhas e apenas em 2 dados , uma abordagem simples, porém limitada e ávida em recursos, faz a codificação sobrecarga mínima, ou seja, não há necessidade de arrays para armazenar dados de todas as 6 linhas:

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

O método awk a seguir lida com grupos ilimitados de 6 linhas e qualquer número de campos por linha.

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"

Saída:

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

Aqui está uma versão bash do script awk acima. O fluxo lógico é o mesmo. Eu adicionei algumas verificações de erro e pular linhas em branco.

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"
    
por 24.06.2015 / 21:37

Tags