Como eu uno dois arquivos CSV, mas somente onde o segundo arquivo corresponde?

2

Eu tenho dois arquivos CSV:

Arquivo de Objetos:

IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John

Arquivo de serviços:

DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow

O arquivo de objetos tem 3000 linhas, o arquivo de serviço tem cerca de 500.

Eu quero criar um novo arquivo que tenha todas as linhas de serviços com campos de objetos adicionados onde uma correspondência na descrição é encontrada. Então a saída desejada seria semelhante a:

DESCRIPTION,OrgIP,Service,IP,MASK
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
    
por MattyM 06.04.2016 / 14:58

4 respostas

1

Usando join :

join --header -t, -11 -23 -a1 <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services) <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects)
join --header -t, -11 -23 -a1 <(
    awk '
        NR > 1 {
            print |
                "sort -t, -k1";
            next
        }
        1
    ' services
) <(
    awk '
        NR > 1 {
            print |
                "sort -t, -k3";
            next
        }
        1
    ' objects
)
  • --header : trata a primeira linha em cada arquivo como cabeçalhos de campo, imprimindo-os sem tentar emparelhá-los
  • -t, : define , como o separador de campos de entrada e saída
  • -11 : junta-se ao campo # 1 de services
  • -23 : junta-se ao campo # 3 de objects
  • -a1 : também imprime linhas não parciais de services
  • <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services) : classifica services na coluna 1 excluindo o cabeçalho
  • <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects) : classifica objects na coluna 3 excluindo o cabeçalho
% cat objects 
IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John
% cat services 
DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow
% join --header -t, -11 -23 -a1 <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services) <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects)
DESCRIPTION,OrgIP,Service,IP,MASK
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
    
por kos 06.04.2016 / 15:32
2

Se você tiver instalado o sqlite3 e o python em seu sistema, poderá usar este link .

O comando sql relevante seria:

./sqlet.py -d',' -A file1.txt -B file2.txt 'select A3,B2,B3,A1,A2 from A LEFT JOIN B ON A3=B1;' | sqlite3

Isso requer que você remova os cabeçalhos dos dois arquivos. O script sqlet deve ser extraído na mesma pasta em que esses dois arquivos são ou modificados adequadamente.

Eu tentei em seu extrato de exemplo. Funciona:

bruni@bruni-Inspiron-5547:~/Downloads$ cat file1.txt
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John
bruni@bruni-Inspiron-5547:~/Downloads$ cat file2.txt
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow
bruni@bruni-Inspiron-5547:~/Downloads$ ./sqlet.py -d',' -A file1.txt -B file2.txt 'select A3,B2,B3,A1,A2 from A LEFT JOIN B ON A3=B1;' | sqlite3
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
    
por Bruni 06.04.2016 / 15:43
1

Se os arquivos não forem muito grandes, que tal awk ?

$ awk -F, 'NR==FNR {a[]= FS  FS ; next}  in a {OFS=","; print ,a[],}' services objects
DESCRIPTION,OrgIP,Service,IP,MASK
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
    
por steeldriver 06.04.2016 / 15:39
1

Você pode fazer:

join -t, -a2 -11 -23 <(head -1 f1.txt; tail -n +2 f1.txt | \
         sort -t, -k1,1) <(head -1 f2.txt; tail -n +2 f2.txt | sort -t, -k3,3)
  • <() é a sintaxe de substituição do processo, bash irá substituí-lo por um descritor de arquivo com a saída do comando dentro dele como o conteúdo

  • head -1 f1.txt; tail -n +2 f2.txt | sort -t, -k1,1 irá sort o primeiro arquivo no primeiro campo da segunda linha para o repouso e a primeira linha será adicionada na parte superior para que possamos usá-lo com join . O mesmo vale para f2.txt com o campo para sort de acordo com três.

  • join apenas ingressará no primeiro campo de f1.txt e terceiro de f2.txt como campos comuns.

Exemplo:

$ cat f1.txt 
DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow

$ cat f2.txt 
IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John

$ join -t, -11 -23 <(head -1 f1.txt; tail -n +2 f1.txt | sort -t, -k1,1) <(head -1 f2.txt; tail -n +2 f2.txt | sort -t, -k3,3)
DESCRIPTION,OrgIP,Service,IP,MASK
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
    
por heemayl 06.04.2016 / 15:44