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

gow*_*awr 5 awk 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>
Run Code Online (Sandbox Code Playgroud)

我正在编写一个 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
}
Run Code Online (Sandbox Code Playgroud)

我将不胜感激任何有关让 gawk 重现混合平台 RS 终结器的指示。

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

更新:

事实证明,此解决方案有效 - 在 Linux 下运行时。当在 Cygwin gawk 下运行时,在 Windows 上,CRLF/LF 区别显然是静音的,它不能按预期工作。我将答案分给了 Peter.O,尽管他基本上重申了我的尝试,因为他以彻底的方式这样做,当我意识到我们在做同样的事情而我的没有用时,这让我质疑我的假设.

Pet*_*r.O 5

您可以使用内置变量 RT

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

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

管道传输时的输出sed -n l- 将CR显示为\r,以及end-of-line作为$-sed表示下一个字符是\n(或end-of-input.

LF$
CRLF\r$
Run Code Online (Sandbox Code Playgroud)

但是,如果要将终止符从 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") }'
Run Code Online (Sandbox Code Playgroud)

管道传输时的输出 sed -n l

was-LF\r$
was-CRLF$
Run Code Online (Sandbox Code Playgroud)

注意: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") } }'
Run Code Online (Sandbox Code Playgroud)