如何在 gawk 中保留混合换行格式?

如何在 gawk 中保留混合换行格式?

我有一个输入文件,其中包含 Unix (LF) 和 Windows (CR/LF) 样式的换行符。 (具体来说,它是来自 Linux 系统的 XML,但它包含一些原始 HTTP 标头,并且 HTTP 更喜欢使用 CRLF 作为标头):

    <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>

我正在编写一个 gawk 脚本来遍历这个文件,对 XML* 进行一些简单的调整,唯一的问题是它读取 LF 和 CRLF 有效的 RS,但只输出 LF,无论那里有什么......本质上,它会删除 CR。

我尝试过各种方法,其中最雄心勃勃的是 RS 的正则表达式匹配和打印 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
}

我非常感谢任何关于让 gawk 重现混合平台 RS 终结者的指示。

* 在这种情况下,简单的调整是将具有正确签名 ID 的行后面的行中的“false”更改为“true”。我完全意识到使用 XML 解析器是完成此任务的正确方法,但对于如此轻量级的需求,我试图避免陷入 XML 解析带来的痛苦和焦虑。

更新:

事实证明,这个解决方案在 Linux 下运行时是有效的。当在 Windows 上的 Cygwin gawk 下运行时,CRLF/LF 区别明显被静音,并且无法按预期工作。我将答案点授予Peter.O,尽管他本质上重申了我正在尝试的事情,因为他以彻底的方式这样做,当我意识到我们在做同样的事情而我的不起作用时,这让我质疑我的假设。

答案1

您可以使用内置变量RT

每次读取记录时都会设置 RT。它包含与 RS(记录分隔符)表示的文本匹配的输入文本。该变量是 gawk 扩展。

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

通过管道传输到时的输出sed -n l- 显示CR作为\r, 和end-of-line作为$- 其中,到sed表示下一个字符是\n(或者end-of-input

LF$
CRLF\r$

但是,如果您想将终止符从 CRLF 切换到 LF 或反之亦然,则有两个操作:

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") }'

通过管道传输到时输出sed -n l

was-LF\r$
was-CRLF$

if注意:当测试不是(主要部分)代码的第一行时, 您将需要使用它们:

  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") } }'

答案2

一个简单的解决方案是仅将 LF 视为行结尾,拉出最终的 CR(如果有),然后将其打印出来。

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

即使最后一个输入行未终止,输出也始终以 LF 结尾。

相关内容