使用sed删除嵌入的换行符

时间:2014-12-09 19:58:05

标签: sed awk

什么是将删除“\ n”字符的sed脚本,但仅当它位于“”字符(分隔字符串)内,而不是实际位于(虚拟)行末尾的\ n? 例如,我想转动此文件

"lalala","lalalslalsa"
"lalalala","lkjasjdf
asdfasfd"
"lalala","dasdf"

(第2行嵌入了\ n)到这个

"lalala","lalalslalsa"
"lalalala","lkjasjdf \\n asdfasfd"
"lalala","dasdf"

(第2行和第3行现已加入,实际换行被替换为字符串\\ n(或任何其他易于识别的字符串,我不挑剔))

我不仅仅想要删除所有其他换行符作为上一个问题,我也不想删除所有换行符,只是那些在引号内的换行符。我并不喜欢sed,如果awk会起作用,那也没关系。

正在操作的文件太大而无法一次装入内存。

2 个答案:

答案 0 :(得分:2)

sed是在单行上进行简单替换的绝佳工具,但对于其他任何你应该使用awk的工具,例如:

$ cat tst.awk
{
    if (/"$/) {
        print prev $0
        prev = ""
    }
    else {
        prev = prev $0 " \\\\n "
    }
}

$ awk -f tst.awk file
"lalala","lalalslalsa"
"lalalala","lkjasjdf \\n asdfasfd"
"lalala","dasdf"

以下是我的原始答案,但在看到@ NeronLeVelu的方法只是测试一行的结尾后,我意识到我这样做的方式太复杂了。你可以用gsub(/"/,"&") % 2替换下面的/"$/并且它的工作方式相同,但上面的代码是相同功能的更简单的实现,现在只要它们不是,就可以处理嵌入的转义双引号#39; t在一行的末尾。

$ cat tst.awk
{ $0 = saved $0; saved="" }
gsub(/"/,"&") % 2 { saved = $0 " \\\\n "; next }
{ print }

$ awk -f tst.awk file
"lalala","lalalslalsa"
"lalalala","lkjasjdf \\n asdfasfd"
"lalala","dasdf"

以上只能在内存中存储1条输出线。它只是从输入行构建输出行,而输出行中的双引号数是奇数,然后在最终包含偶数双引号时输出输出行。

如果你引用的字符串中的双引号可能会被\"转义,而不是"",但是你没有在你发布的示例输入中显示,所以希望你不要&# 39;没有那种情况。如果您遇到这种情况,则需要编写/使用真正的CSV解析器。

答案 1 :(得分:1)

sed -n ':load
/"$/ !{N
      b load
      }
:cycle
s/^\(\([^"]*"[^"]*"\)*\)\([^"]*"[^"]*\)\n/\1\3 \\\\n /
t cycle
p' YourFile
  • 将线条加载到工作缓冲区中,直到找到一条近线(以"结尾)或终点
  • 替换任意一个开头/关闭{\ n} {}之后的任何\ n,后跟一个",其中任何其他字符"介于文件开头之间的"新行(实际上是通过启动字符串替换起始字符串+ \ n并转义新行)
  • 如果发生任何替换,请重试另一个(:cyclet cycle
  • 打印结果
  • 继续直到文件结尾

感谢@Ed Morton关于转义新线路的评论