我有一个包含 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,尽管他基本上重申了我的尝试,因为他以彻底的方式这样做,当我意识到我们在做同样的事情而我的没有用时,这让我质疑我的假设.
您可以使用内置变量 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)