Mesclando no Unix

1

Eu tenho um arquivo CSV com barras verticais ( | ) como delimitador, como abaixo, para o qual preciso aplicar a técnica de mesclagem no Unix. O arquivo contém centenas de milhares de registros (quatro campos), mas eu dei apenas cinco registros para facilitar a leitura.

field1 |field2 | field3 |field4|
1|abc|def|ghi|
4|ijk|
|lmn|
5||opq|rst|
8|
uvw||xyz|
10|hjg|jsh|nbm|

E eu quero o resultado de saída como

field1|field2|field3|field4|
1|abc|def|ghi|
4|ijk||lmn|
5||opq|rst|
8|uvw||xyz|
10|hjg|jsh|nbm|
    
por Sankar 25.09.2018 / 19:59

3 respostas

2

Com o GNU sed:

sed ':loop /\(.*|\)\{4\}.*/ !{N; s/\n//; b loop}; s/ *| */|/g' file

O comando dissecado:

:loop

O : sinaliza um rótulo que podemos usar para filiais. "loop" é apenas o nome que escolhi para o marcador.

/\(.*|\)\{4\}.*/

É um regex de seletor de linha que corresponde a linhas que contêm 4 símbolos de pipe, cada um permitido ser precedido por zero ou mais caracteres arbitrários ( .*| ), com zero ou mais caracteres arbitrários permitidos para seguir o último canal.

!{ ... }

Aplica os comandos nos colchetes a qualquer linha que não corresponda à regex anterior.

N; s/\n//; b loop

N concatena a linha atual em espaço padrão com um símbolo de nova linha e a próxima linha do arquivo de origem, então s/\n// remove o símbolo de nova linha e b loop ramificações de volta ao rótulo nós definimos no início, então a linha concatenada será comparada com a regex novamente.

Por último

s/ *| */|/g

será aplicado a qualquer linha no espaço padrão antes de sua saída. Isso remove todos os espaços ao redor dos símbolos de tubos.

    
por 25.09.2018 / 20:25
0

Estou assumindo que você não quer todas essas linhas em branco.

$ cat file
1|abc|def|ghi|
4|ijk|
|lmn|
5||opq|rst|
8|
uvw||xyz|
10|hjg|jsh|nbm|

$ awk -F'|' '{while (NF < 5) {getline nextline; $0 = $0 nextline}}1' file
1|abc|def|ghi|
4|ijk||lmn|
5||opq|rst|
8|uvw||xyz|
10|hjg|jsh|nbm|

Atualização para a edição da pergunta: remova os espaços em branco em torno do separador de campo

awk -F'[[:blank:]]*[|][[:blank:]]*' -v OFS='|' '
    {while (NF < 5) {getline nextline; $0 = $0 nextline}; $1=$1; print} 
' file
    
por 25.09.2018 / 20:18
0

Se o uso do Vim for uma opção:

vim -Nesc 'g!/\(.*|\)\{4\}$/j!' -cwq input.txt
  • -Nes executa o Vim no modo de script, facilitando a automação
  • -c ... executa comandos do Vim após abrir o arquivo
  • g!/\(.*|\)\{4\}$/j! - em cada linha :g , isso não ! match /\(.*|\)\{4\}$/ (uma regex que corresponde a 4 pipes separados por qualquer coisa), junte a próxima linha a ela ( :j ).
  • wq - salve e saia.
por 26.09.2018 / 09:43