Mesclando duas colunas de arquivos em ordem

3

Eu quero mesclar dois arquivos.

Arquivos A.txt

001;abc;def;ghi;jkl;pqr
002;abc;def;ghi;jkl;pqr
003;abc;def;ghi;jkl;pqr
004;abc;def;ghi;jkl;pqr
005;abc;def;ghi;jkl;pqr

Segundo arquivo B.txt

001;mno
002;mno
003;mno
004;mno
005;mno

para ter um arquivo de texto C.txt

001;abc;def;ghi;jkl;mno;pqr

Eu sou capaz de mesclar esses dois arquivos, mas não sei como inserir a saída do arquivo B mno antes de pqr .

    
por user62687 13.03.2014 / 20:19

5 respostas

1

join imprimirá cada linha de arquivos de entrada classificados que tenham o mesmo primeiro campo * (por padrão). Então, definindo o delimitador de campo ( -t ) para ; você recebe:

$ join -t\; A.txt B.txt 
001;abc;def;ghi;jkl;pqr;mno
002;abc;def;ghi;jkl;pqr;mno
003;abc;def;ghi;jkl;pqr;mno
004;abc;def;ghi;jkl;pqr;mno
005;abc;def;ghi;jkl;pqr;mno

Combinando isso com awk para mudar as posições de campo:

$ join -t\; A.txt B.txt | 
    awk -F';' -v OFS=';' '{k=$NF; $NF=$(NF-1); $(NF-1)=k; print;}'
001;abc;def;ghi;jkl;mno;pqr
002;abc;def;ghi;jkl;mno;pqr
003;abc;def;ghi;jkl;mno;pqr
004;abc;def;ghi;jkl;mno;pqr
005;abc;def;ghi;jkl;mno;pqr
    
por 13.03.2014 / 23:38
6

Você pode usar join

join -t\; -o0,1.2,1.3,1.4,1.5,2.2,1.6 a.txt b.txt

-t\; usa ponto-e-vírgula como separador de campo e a lista -o informa quais campos serão impressos em qual ordem. Isso não imprimirá linhas em nenhum dos arquivos sem correspondência na outra; para conseguir que você pode adicionar -a1 (para o primeiro arquivo) ou -a2 (para o segundo).

    
por 13.03.2014 / 22:37
2

Tente isto:

awk -F';' 'FNR==NR{a[$1]=$NF;next}{
    for(i=1;i<=NF;i++){
        if($i<a[$1]){
            printf("%s;",$i)
        } else {
            printf("%s;%s",a[$1],$i)
        }
    }
    print ""}' B.txt A.txt

Saída:

001;abc;def;ghi;jkl;mno;pqr
002;abc;def;ghi;jkl;mno;pqr
003;abc;def;ghi;jkl;mno;pqr
004;abc;def;ghi;jkl;mno;pqr
005;abc;def;ghi;jkl;mno;pqr
    
por 13.03.2014 / 20:50
1

Aqui está um menor awk :

awk 'BEGIN{FS=OFS=";"}NR==FNR{a[$1]=$2;next}$NF=a[$1]FS$NF' fileb filea

$ cat filea
001;abc;def;ghi;jkl;pqr
002;abc;def;ghi;jkl;pqr
003;abc;def;ghi;jkl;pqr
004;abc;def;ghi;jkl;pqr
005;abc;def;ghi;jkl;pqr

$ cat fileb     # Intentionally modified fields to show they map correctly
001;mno
002;nno
003;qno
004;fno
005;sno

$ awk 'BEGIN{FS=OFS=";"}NR==FNR{a[$1]=$2;next}$NF=a[$1]FS$NF' fileb filea
001;abc;def;ghi;jkl;mno;pqr
002;abc;def;ghi;jkl;nno;pqr
003;abc;def;ghi;jkl;qno;pqr
004;abc;def;ghi;jkl;fno;pqr
005;abc;def;ghi;jkl;sno;pqr
    
por 14.03.2014 / 02:07
1

Então, é isso que eu usei para obter o material de origem:

cat <<F1 >/tmp/f1 ; cat <<F2 >/tmp/f2
$(for i in 1 2 3 4 5 ; do { \
    printf "00%s" $i ; printf ";%s" \
        abc def ghi jkl pqr ; echo ; } ; done)
 F1
 $(for i in 1 2 3 4 5 ; do {\ 
    printf "00%s" $i ; echo ";mno" ; } ; done)
 F2

Fornece:

001;abc;def;ghi;jkl;pqr
002;abc;def;ghi;jkl;pqr
003;abc;def;ghi;jkl;pqr
004;abc;def;ghi;jkl;pqr
005;abc;def;ghi;jkl;pqr
001;mno
002;mno
003;mno
004;mno
005;mno

Eu testei isso de várias maneiras, e este é o comando resultante:

% sed -e 'R /tmp/f2' /tmp/f1 |\
    sed -r 'N;s/(.*)(;[^;]*)\n[^;]*(.*)//'

Isso é GNU sed only - porque o GNU oferece a função R que podemos ler em um arquivo separado linha por linha em sincronia com nossa entrada. Isso significa sem ramificação e sem loop. Dessa forma, espero que sed trabalhe com mais eficiência do que awk , porque não precisaria ler o conteúdo completamente na memória antes de operar e pode operar em uma transmissão ao vivo.

Eu tentei fazer isso funcionar sem a invocação |pipe e segundo sed , mas porque sed anexou / tmp / f2 ao seu próprio stdout nada que eu tentei permitiu edite no fluxo sem o |pipe . sed primeiro agrupa os dois arquivos no fluxo e edita o resultado no outro lado do |pipe .

De qualquer forma, um |pipe ainda é transmitido, mas você precisa de dois sed s. Execute o comando sed acima em seus dados e:

OUTPUT
> 001;abc;def;ghi;jkl;mno;pqr
> 002;abc;def;ghi;jkl;mno;pqr
> 003;abc;def;ghi;jkl;mno;pqr
> 004;abc;def;ghi;jkl;mno;pqr
> 005;abc;def;ghi;jkl;mno;pqr

Veja como funciona:

sed -r 'N;s/(.*)(;[^;]*)\n[^;]*(.*)//'
  • N porque já sabemos que sed está anexando cada linha sucessiva de f2 àquelas em f1 , a primeira coisa que fazemos depois de receber uma linha é Puxe o N ext.
  • s tendo juntado as duas linhas que precisamos no espaço padrão, iniciamos a função s earch and replace

    001; abc; def; ghi; jkl ; pqr \ n001; mno

  • \ 1 (. *) primeiro informe sed to ( group * tudo que for encontrado ) da parte mais à esquerda do espaço de padrões na referência de referência até ...

    001; abc; def; ghi; jkl * ; pqr * \ n001; mno

  • \ 2 (; [^;] *) \ n encontra uma string que consiste em um ...

    • ; ponto e vírgula então ...
    • [^;] * uma string consistindo inteiramente de ^ no; ponto e vírgula imediatamente seguido por
    • \ n o caractere \n ewline adicionado quando extraímos a linha f2 com N e o qual será descartado
    • () Dessa forma, fazemos referência ao ( do último campo delimitado por ponto-e-vírgula ) da linha em f1 to
  • [^;] * começando com a linha f2 , pesquisamos e descartamos todos os caracteres até encontrarmos um ponto-e-vírgula e

    001; abc; def; ghi; jkl; pqr \ n001 * ; mno *

  • \ 3 (. *) armazenamos tudo o que resta na backreference

  • \ 1 \ 3 \ 2 uma vez que dividimos a string, pois exigimos que tudo o que resta é colocá-la de volta na ordem correta , então inserimos antes de e terminamos com esse ciclo de substituição de pesquisa até recebermos uma nova linha

por 13.03.2014 / 22:06