在 awk 中用换行符替换“\n”

Posted

技术标签:

【中文标题】在 awk 中用换行符替换“\\n”【英文标题】:Replace "\n" with newline in awk在 awk 中用换行符替换“\n” 【发布时间】:2014-08-25 19:18:22 【问题描述】:

我正在跟踪日志,它们输出 \n 而不是换行符。

我想我会将tail 传递给awk 并进行简单的替换,但是我似乎无法逃脱正则表达式中的换行符。在这里,我用cat 而不是tail 来展示我的问题:

test.txt:

John\nDoe
Sara\nConnor
cat test.txt | awk -F'\\n' ' print $1 "\n" $2 '

期望的输出:

John
Doe
Sara
Connor

实际输出:

John\nDoe

Sara\nConnor

所以看起来\\n 与 test.txt 中名字和姓氏之间的\n 不匹配,而是每行末尾的换行符。

看起来\\n 不是在终端中转义的正确方式对吗?这种转义方式在例如崇高的文字:

【问题讨论】:

【参考方案1】:

这个怎么样?

$ cat file
John\nDoe
Sara\nConnor

$ awk 'gsub(/\\n/,"\n")1' file
John
Doe
Sara
Connor

【讨论】:

你为什么使用awksed 似乎更适合编辑文件。 op 标记了 awk 标签。 您可以将"\n" 更改为RS 并得到awk 'gsub(/\\n/,RS)1' 也许我不应该标记这个awk,但我做了,这个答案有效。但是sed 似乎更适合这项任务?问题是 sed 在 Mac OSX 上的行为很奇怪,请参阅 @DarkDust 和 @Ed Morton 的答案。 @Cotten 我不是强迫你。寻找最适合您的任何其他解决方案。【参考方案2】:

使用 GNU 的 sed,解决方案非常简单,因为 @hek2mgl 已经回答了(恕我直言,它应该可以在任何地方工作,但不幸的是没有)。

但在Mac OS X 和other *BSD UNIXes 上执行此操作时有点棘手。

最好的方法是这样的:

sed 's/\\n/\'$'\n''/g' <<< 'ABC\n123'

那么当然还有 AWK,如果你想使用它,@AvinashRaj 有正确的答案。

【讨论】:

错误,没有。反过来说:GNU 的 sed 正在扩展 POSIX sed;这就是为什么它首先需要--posix 我认为您的语法有点偏离 - 在 sed 处理脚本之前,在脚本中插入文字换行符(由 $'\n' 生成)应该是 sed 's/\\n/\'$'\n''/g'。我不确定 shell 在你的 sed 脚本的两半('s/\\n/\''\n/g')之间对独立的$ 做了什么。 所以,让我们实际看一下POSIX standard:问题在于标准没有指定s 的第二部分(“替换”)是否应解释\n。由于它不是 BRE 并且“\”在这里具有特殊含义,我会说它不应该。 BSD sed 的 POSIX notes 声明历史版本没有并丢弃了“\”(参见第 16 点)。所以两者都是 POSIX 兼容的,因为标准没有指定行为。 是的,发生的事情是,在 sed 尝试执行脚本之前,shell 正在评估 $'\n/g',并且扩展为文字换行符,然后是 /g,因此它通过同时发生“工作”。在 / 之后,它不适用于 shell 将扩展的不同字符 - /g 恰好是无害的。 +1,但请注意ANSI C-quoted string、$'\n' 的使用使解决方案依赖于外壳;不过幸运的是,流行的 shell(bashzshksh)确实支持这一点,但只有 POSIX 功能的 shell(例如 dash)不支持。【参考方案3】:

这适用于任何系统上的任何 sed,因为它是在 sed 中使用换行符的可移植方式:

$ sed 's/\\n/\
/' file
John
Doe
Sara
Connor

如果您的输入可能包含foo\\nbar 之类的行,而\\ 旨在成为转义的反斜杠,那么您不能使用您要求的简单替换方法。

【讨论】:

是的,你是对的。你能解释一下为什么GNU sed --posix 的行为与 BSD sed 不同(它也声称与 POSIX 兼容)。问题是由GNU sed --posix 无法正常工作还是由 BSD sed 不兼容 POSIX 引起的? 抱歉,不,我需要阅读 sed 的 POSIX 规范才能弄清楚这一点,而且生命太短了......不过,我会说,BSD awk 在某些方面被破坏了(例如解析打印语句中未加括号的三元表达式)所以也许他们的 sed 也是如此? 我也需要,想也许你已经知道了... :) thx 。 +1 解决方案 @hek2mgl,根据 POSIX, 的含义紧跟除'&amp;'&lt;backslash&gt;、数字或用于此的分隔符之外的任何字符命令,未指定。,因此 GNU sed 行为是一致的,输出 \n 或重新启动计算机的 sed 也是如此。使用 \n脚本 将不符合标准(正是因为该行为未指定)。【参考方案4】:

为什么要为此使用awksed?使用perl

perl -pe 's/\\n/\n/g' file

通过使用perl,您不必考虑 posix 合规性,它通常会提供更好的性能,并且在所有(大多数)平台上都保持一致。

【讨论】:

因为不是每个系统都安装了 perl。【参考方案5】:

我会使用sed:

sed 's/\\n/\n/g' file

【讨论】:

这对我不起作用:sed 's/\\n/\n/g' test.txt 输出:line1:JohnnDoe line2:SaranConnor 应该的。试试:sed 's/\\n/\n/g' &lt;&lt;&lt; 'ABC\n123' sed 's/\\n/\n/g' &lt;&lt;&lt; 'ABC\n123' 给了我ABCn123。这是平台问题吗?我在 OS X 上使用 zsh sed --posix 's/\\n/\n/g' &lt;&lt;&lt; 'ABC\n123' 有效。抱歉,请使用 Linux。我不是 OSX 支持者,我已经厌倦了支持这一点,并且永远不会明白为什么应该使用 Mac 进行黑客攻击。 (这不是针对您个人) BSD 的sed 没有--posix,它已经符合POSIX。 GNU 的sed 对POSIX 有很多(有用的)扩展,--posix 应该禁用这些扩展。我找到了一个answer with a solution that works on all systems(在 Mac 和 Linux 上测试过)。【参考方案6】:

我以前也遇到过这个问题,但我发现最干净的方法是使用内置的printf

printf "$(cat file.txt)" | less

这是一个处理输出中嵌入 aws iam 的 json 策略的真实示例,文件 file.txt 包含:


  "registryId": "111122223333",
  "repositoryName": "awesome-repo",
  "policyText": "\n  \"Version\" : \"2008-10-17\",\n  \"Statement\" : [ \n    \"Sid\" : \"AllowPushPull\",\n    \"Effect\" : \"Allow\",\n    \"Principal\" : \n      \"AWS\" : [ \"arn:aws:iam::444455556666:root\", \"arn:aws:iam::444455556666:user/johndoe\" ]\n    ,\n    \"Action\" : [ \"ecr:BatchCheckLayerAvailability\", \"ecr:BatchGetImage\", \"ecr:CompleteLayerUpload\", \"ecr:DescribeImages\", \"ecr:DescribeRepositories\", \"ecr:GetDownloadUrlForLayer\", \"ecr:InitiateLayerUpload\", \"ecr:PutImage\", \"ecr:UploadLayerPart\" ]\n   ]\n"

在应用上述(没有更少)之后,你会得到:


  "registryId": "111122223333",
  "repositoryName": "awesome-repo",
  "policyText": "
  "Version" : "2008-10-17",
  "Statement" : [ 
    "Sid" : "AllowPushPull",
    "Effect" : "Allow",
    "Principal" : 
      "AWS" : [ "arn:aws:iam::444455556666:root", "arn:aws:iam::444455556666:user/johndoe" ]
    ,
    "Action" : [ "ecr:BatchCheckLayerAvailability", "ecr:BatchGetImage", "ecr:CompleteLayerUpload", "ecr:DescribeImages", "ecr:DescribeRepositories", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:UploadLayerPart" ]
   ]
"

请注意,“policyText”的值本身就是一个包含 json 的字符串。

【讨论】:

【参考方案7】:

除了接受的答案之外,OP 还询问了 tail,并且在某些 unix 变体上,例如 ubuntu,您需要将 -W interactive 添加到 awk

tail -f error.log | awk -W interactive 'gsub(/\\n/,"\n")1'

【讨论】:

以上是关于在 awk 中用换行符替换“\n”的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Emacs 中用换行符替换字符?

如何在 Vim 中用换行符替换字符

在 PHP 中用一个空格替换多个空格和换行符

在java中用','替换'\ n'

javascript 在 createTextNode 中用 <br> 替换 \n

如何使用 C# 在给定文本中用忽略空格、回车或换行符替换字符串