Como preservar os formatos de alimentação de linha mistos no gawk?

4

Eu tenho um arquivo de entrada que contém as novas linhas de estilo Unix (LF) e Windows (CR / LF). (Especificamente, é XML de um sistema Linux, mas contém alguns cabeçalhos HTTP brutos e HTTP prefere CRLF para cabeçalhos):

    <response_page cause="default">
      <response_type>custom</response_type>
      <response_header>HTTP/1.1 200 OK^M
Cache-Control: no-cache^M
Pragma: no-cache^M
Connection: close</response_header>

Estou trabalhando em um script gawk para percorrer este arquivo para fazer alguns ajustes simples no XML * e o único problema é que ele lê o RS válido de LF e CRLF, mas só gera LF independentemente do que estava lá .. Em essência, retira os CRs.

Eu tentei várias coisas, sendo as mais ambiciosas as correspondências regex para RS e a impressão RT:

BEGIN { RS = "\r\n|\n"; go = "no" }
(go ~ /yes/) { 
    sub(/false/, "true", $0)
    go = "no"
}
($0 ~ /<signature signature_id="200000017">/) { 
    print "Found signature!"
    go = "yes"
} 
{ 
    printf $0 RT
}

Eu agradeceria muito qualquer indicação sobre a obtenção do gawk para reproduzir terminadores RS de plataforma mista.

* Nesse caso, o simples ajuste é alterar 'falso' para 'verdadeiro' na linha após a linha com o ID de assinatura correto. Eu compreendo perfeitamente que usar um analisador XML seria a maneira correta de fazer isso, mas para uma necessidade tão leve estou tentando evitar a compra do uivo de dor e angústia que é a análise XML.

Atualização:

Como se vê, esta solução funciona - quando executado no Linux. Quando executado sob o Cygwin gawk, no Windows, a distinção CRLF / LF aparentemente é silenciada e não funciona como esperado. Eu estou concedendo os pontos de resposta para Peter.O, mesmo que ele basicamente tenha reiterado o que eu estava tentando, porque ele fez isso de uma forma completa que me fez questionar minhas suposições quando percebi que estávamos fazendo a mesma coisa e que a minha não funcionou. .

    
por gowenfawr 08.06.2015 / 22:29

2 respostas

4

Você pode usar a variável interna RT

RT is set each time a record is read. It contains the input text that matched the text denoted by RS, the record separator. This variable is a gawk extension.

printf '%s\n' LF CRLF$'\r' | 
  gawk 'BEGIN { RS = "\r\n|\n" }
       { printf($0 RT) }'

Saída quando canalizado para sed -n l - que mostra CR como \r e end-of-line como $ - que, para sed , significa que o próximo caractere é \n (ou end-of-input .

LF$
CRLF\r$

No entanto, se você quiser alternar o terminador de CRLF para LF ou vice-versa, as duas ações são:

printf '%s\n' was-LF was-CRLF$'\r' | 
  gawk 'BEGIN { RS = "\r\n|\n" }
        RT == "\r\n" { printf($0 "\n") }
        RT == "\n"   { printf($0 "\r\n") }'

Saída quando canalizado para sed -n l

was-LF\r$
was-CRLF$

Nota: Você precisará usar if para os testes quando eles não forem as primeiras linhas do código (seção principal):

  gawk 'BEGIN { RS = "\r\n|\n" }
        { # some processing code here (before the tests)
          if( RT == "\r\n" ) { printf($0 "\n") }
          if( RT == "\n")    { printf($0 "\r\n") } }'
    
por 08.06.2015 / 23:03
1

Uma solução direta é tratar apenas o LF como um final de linha, puxar o CR final, se houver, e imprimi-lo.

{ CR = (sub(/\r$/,"") ? "\r" : "") }
… { … print "stuff" CR }

A saída sempre terminará com um LF, mesmo se a última linha de entrada não for terminada.

    
por 09.06.2015 / 03:22

Tags