Remova todas as quebras de linha após o retorno de carro (^ M) e junte as linhas

2

edit: Agora que recebi respostas, marquei uma por @KamilMaciorowski que se encaixa melhor no título como resposta, mas esta resposta por @oliv , na verdade, eram mais adequados à minha necessidade real para o meu objetivo principal. (Para processar o arquivo csv com quebras consistentemente no awk.)

Então, no caso de você estar procurando por um despertador na mesma situação, recomendo que verifique primeiro!

Por favor me ajude a preparar alguns milhares de arquivos csv prontos para awk processar! Parte do campo tem quebras de linha dentro do campo e isso faz com que awk as processe como vários registros. No entanto, essas quebras de linha problemáticas só acontecem onde ^ M é inserido, então eu apenas preciso remover ^ M e quebra de linha de todos eles.

* Esses ^M s são de fato caractere de quebra de linha, não literal caret & letra M string. Este arquivo é gerado para que o .net analise e processe, mas eu não trabalhei no desenvolvimento de aplicativos em nenhum lado de produção / leitura de arquivos, então eu realmente não sei como ele é analisado com sucesso. Ele é usado exclusivamente para campos em determinadas colunas com strings multilinha (comentários).

Então, como você faz isso (csv com 1 cabeçalho e 2 registros. Algum campo tem quebras de linha nele precedidas por ^ M):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a^M
2-2_b^M
2-2_c", "2-3"

assim? (csv com 1 cabeçalho e 2 registros sem quebras de linha dentro de cada um deles.):

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a2-2_b2-2_c", "2-3"

Eu tentei removê-los com sed , mas ouvi dizer que não há como processar e não entendi o motivo.

for file in *.csv; do
    sed -e "s/^M//" $file > sedded/$file;
done

De qualquer forma, eu entendo isso:

"header_1", "header_2", "header_3"
"1-1", "1-2", "1-3"
"2-1", "2-2_a
2-2_b
2-2_c", "2-3"

Eu tentei usar algo como "s/^M\n/" e não funciona como eu suspeitava. Devo usar uma ferramenta completamente diferente como vim ? Desde que funcione para milhares de arquivos de uma só vez (cada um contendo ~ 500 linhas, e eu realmente não me importo com o tempo que leva para processar), estou bem com qualquer tipo de resolução. Apenas pensei que sed era o caminho. (Eu estou ok para usar o comando DOS / powershell se for mais fácil ou mais direto!)

    
por AlexKlaus 21.06.2018 / 10:06

2 respostas

1

Se esses ^M -s forem de fato caracteres de quebra de linha, não literal caret & Seqüências de letras M, então elas são o que chamamos de \r , CR ou 0x0d (compare esta resposta minha, o começo disto ).

Seu comando

sed -e "s/^M//"

não remove \r ; nem sequer remove literal ^M . O comando significa "pegue uma linha, procure uma letra M que esteja no início da linha ( ^ , veja isto ), substitua-o por nada.

Observação sed entende \r . Ainda sed -e 's/\r//' não é exatamente o que você precisa. Ele remove \r , mas você também precisa remover o seguinte \n . Você pode querer tentar sed -e 's/\r\n//' , isso também irá falhar. O problema é que sed é uma ferramenta de texto e trata \n como um separador. Trecho de info sed (ênfase minha):

sed operates by performing the following cycle on each lines of input: first, sed reads one line from the input stream, removes any trailing newline, and places it in the pattern space. Then commands are executed; […].

Isso significa que normalmente \n não pertence a nenhuma string processada com s/… (ou outro comando sed ). Por esse motivo, concatenar poucas linhas não é fácil. Ainda pode ser feito . Este é o comando que você precisa:

sed -e ': start; /\r$/{ s/\r$//; N; s/\n// }; /\r$/b start'

Explicação:

  • : start é um rótulo.
  • Se a linha contiver \r (ou seja, ^M , 0x0d character) no final ( $ ), execute o bloco {} , que é:
    • substitua \r no final sem nada,
    • acrescente uma linha adicional da entrada ( N ),
    • substitua \n que separa a linha adicional dos dados anteriores.
  • Se o resultado contiver \r no final (o que significa que a linha adicional o trouxe, por isso precisamos adicionar outra linha), salte para start .
por 21.06.2018 / 13:39
1

Supondo que existem 3 campos em cada linha, e não há qualquer aspas duplas dentro de qualquer valor, você pode usar este script GNU awk:

awk -v FPAT='"[^"]*"' '{while(NF!=3){p=$0;getline;gsub("^",p)}; p=""}1' file

FPAT define como um campo deve ser, ou seja, qualquer coisa envolvendo aspas duplas.

A instrução awk cria um registro obtendo linhas do arquivo até que haja três campos.

    
por 21.06.2018 / 10:51

Tags