Manipulando 3 arquivos usando o awk

9

Considere os seguintes arquivos:

file1:

boo,8,1024
foo,7,2048

file2:

foo,0,24,154
noo,0,10,561

file3:

24,154,7,1024,0

O que eu preciso é ir para o Arquivo1 e verificar se $2==7; se for verdade, tomar $1, $2e $3de File1 ; agora eu tenho que comparar se $1de File1 igual a $1de File2 ; se for verdade, eu tenho que tomar $3e $4de File2 que não existem em File1 , então eu tenho que ir para File3 e verifique se $1a partir File3 é igual a $3de File2 , e $2de File3 é igual a $4de File2 ; se sim, então eu tenho que verificar se $2do arquivo1é igual a $3do arquivo3 , se essa condição for verdadeira, tenho que comparar $3do arquivo1 com $4do arquivo3 , se $3do arquivo1 for mais do que $4do arquivo3 .

Eu tentei o seguinte script:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

A saída desejada é:

foo,7,2048,24,154,1024
Eng7
fonte

Respostas:

9

Isso funcionou para mim:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

Explicação :

  • A primeira linha ( FNR==1{++f}) incrementa o índice do arquivo para determinar posteriormente em qual arquivo estamos 1-3.
  • file1: se for $2igual7
    • preencha uma matriz a1com $1como índice e a2com $2como índice e $3como valor
    • anote a ovariável (saída) com os 3 primeiros campos
  • file2: se $1de file2iguais $1de file1(prevously escrito em a1)
    • anexar $3e $4à variável de saída o.
    • preencha uma matriz a3com $3como índice e $4como valor.
  • arquivo3: se:
    • $1é igual a file2s $3(índice de a3)
    • $2é igual a file2s $4(valor de a3)
    • $3é igual a file1s $2(índice de a2)
    • $4é menor que file1s $3(valor de a2)
  • então:
    • imprima o valor de o.
caos
fonte
Existe uma necessidade de barra invertida (além da última)? que tal BEGINFILE (em vez de FNR == 1)?
Archemar 08/09/2015
@Archemar BEGINFILE e ENDFILE são extensões gawk e as barras invertidas podem ser removidas, eu as inseri, para melhor legibilidade: você pode escrever tudo isso em uma única linha, mas não ficaria bem
caos
@chaos, obrigado, mas infelizmente sempre retorna nulo.
Eng7
@ Azizieh7 Eu testei com mawk e gawk com seus 3 arquivos de exemplo de entrada. Para mim funcionou. Você usa diferentes arquivos de entrada ou codificações / quebras de linha?
caos
@chaos, existem quebras de linha diferentes no arquivo3, mas eu uso tr -d '\ 015' para superar isso.
Eng7
1

Solução TXR:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

Corre:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

Mas o observador astuto notará que o 7 não foi especificado em nenhum lugar do código, aparecendo apenas na saída! Isso ocorre porque o código está marcando todos os registros file1e imprime todas as combinações que atendem às correspondências e restrições . A única nos dados da amostra é aquele com val0ser 7.

Se houvesse mais combinações encontradas, poderia ser restrito a 7uma dessas:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

A linguagem de extração de padrões TXR fornece aqui uma grande correspondência de padrões com referências remotas implícitas através da repetição de nomes de variáveis, abrangendo vários arquivos, com padrões de extração de várias linhas e restrições não textuais, além de efeitos colaterais incorporados, como saída, etc. .

A solução Awk aceita traduziu cuidadosamente a awkmacro TXR Lisp :

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

Corre:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

A ,1024parte necessária na saída está ausente; o original "Awk Classic" tem esse comportamento.

Kaz
fonte