UNIX - comando para dividir o arquivo em vários arquivos com todas as linhas para cada 3 valores exclusivos em uma coluna

2

Considere o arquivo de entrada abaixo. Arquivo de entrada:

C1|C2|C3|C4|C5|C6
0|1|2|3|0-1-2-3|4
0|2|2|4|0-1-2-3|5
0|1|2|3|1-3-2-4|4
0|1|2|3|1-1-3-4|4
0|1|2|3|1-1-3-4|5
0|1|2|3|4-5-2-6|4
0|1|2|3|4-5-2-6|6
0|4|5|3|7-4-2-4|4
0|1|2|3|7-4-2-5|4
0|1|2|3|7-4-2-5|5
0|1|2|3|7-4-2-5|6
0|1|2|3|7-5-2-6|5

Com base no campo 5, por exemplo, 0-1-2-3 no primeiro registro, os arquivos divididos de saída são esperados como abaixo Dividir arquivo1:

C1|C2|C3|C4|C5|C6
0|1|2|3|0-1-2-3|4
0|2|2|4|0-1-2-3|5
0|1|2|3|1-3-2-4|4
0|1|2|3|1-1-3-4|4
0|1|2|3|1-1-3-4|5

Dividir arquivo 2:

C1|C2|C3|C4|C5|C6
0|1|2|3|4-5-2-6|4
0|1|2|3|4-5-2-6|6
0|4|5|3|7-4-2-4|4
0|1|2|3|7-4-2-5|4
0|1|2|3|7-4-2-5|5
0|1|2|3|7-4-2-5|6

Dividir arquivo 3:

C1|C2|C3|C4|C5|C6
0|1|2|3|7-5-2-6|5

Com base na coluna 5, para cada 3 valores exclusivos na coluna, o arquivo deve ser dividido e deve ter todas as linhas nas quais o valor da coluna 5 é repetido. Alguém pode me ajudar com isso?

    
por unixlearner 22.08.2017 / 13:16

3 respostas

4

Um trabalho para o awk. Algo como:

awk -F'|' -v fileformat="/abc/output/file_%04d.txt" -v max=3 -v field=5 '
  NR == 1 {header = $0; next}
  ! ($field in seen) {
    seen[$field]
    if (++n % max == 1) {
      close(out)
      out = sprintf(fileformat, ++f)
      print header > out
    }
  }
  {print > out}' < /abc/input/a.txt
    
por 22.08.2017 / 13:30
1
Solução

awk :

awk -F'|' 'NR==1{ h=$0; f=0; c=1 }NR>1{ 
              a[$5]; if(length(a)>3) { f=0;c++; delete a }; 
              fn="file"c".txt"; if(!f) print h > fn; print > fn; f++ 
           }' file
  • h=$0 - cabeçalho linha

  • f=0 - sinalizador apontando para o momento da impressão da linha de cabeçalho no próximo novo arquivo

  • c=1 - sufixo do nome do arquivo (incrementado para cada novo arquivo)

  • a[$5] - matriz de indexação a com valores exclusivos do 5º campo

  • if(length(a)>3) { f=0;c++; delete a } - iniciando o próximo novo nome de arquivo ( c++ ) ao obter 3 valores exclusivos. ( delete a - elimina itens do array a )

  • fn="file"c".txt" - nome de arquivo atual

Visualizando resultados:

for f in file[0-9]*.txt; do echo "$f"; cat "$f"; echo; done

A saída:

file1.txt
C1|C2|C3|C4|C5|C6
0|1|2|3|0-1-2-3|4
0|2|2|4|0-1-2-3|5
0|1|2|3|1-3-2-4|4
0|1|2|3|1-1-3-4|4
0|1|2|3|1-1-3-4|5

file2.txt
C1|C2|C3|C4|C5|C6
0|1|2|3|4-5-2-6|4
0|1|2|3|4-5-2-6|6
0|4|5|3|7-4-2-4|4
0|1|2|3|7-4-2-5|4
0|1|2|3|7-4-2-5|5
0|1|2|3|7-4-2-5|6

file3.txt
C1|C2|C3|C4|C5|C6
0|1|2|3|7-5-2-6|5
    
por 22.08.2017 / 14:31
1
#!/bin/bash

awk -F '|' '
    function print_to_file(str) {
        print str > "file_"file_num;    
    }
    NR == 1 {header = $0;}
    NR > 1 {
        if(!buf) {
            file_num = 1;
            print_to_file(header);
        }
        if(buf != $5) {
            buf = $5;
            cnt++;
        }
        if(cnt > 3) {
            cnt = 1;
            file_num++;
            print_to_file(header);
        }
        print_to_file($0);
    }
' input.txt

Saída:

$ tail -n +1 -- file_* # display content of all files with their filenames

==> file_1 <==
C1|C2|C3|C4|C5|C6
0|1|2|3|0-1-2-3|4
0|2|2|4|0-1-2-3|5
0|1|2|3|1-3-2-4|4
0|1|2|3|1-1-3-4|4
0|1|2|3|1-1-3-4|5

==> file_2 <==
C1|C2|C3|C4|C5|C6
0|1|2|3|4-5-2-6|4
0|1|2|3|4-5-2-6|6
0|4|5|3|7-4-2-4|4
0|1|2|3|7-4-2-5|4
0|1|2|3|7-4-2-5|5
0|1|2|3|7-4-2-5|6

==> file_3 <==
C1|C2|C3|C4|C5|C6
0|1|2|3|7-5-2-6|5
    
por 23.08.2017 / 10:04