如何使用 sed 替换换行符(\ n)?

如何将换行符(“ \n ”)替换为空格(“ “)使用sed命令?

我尝试失败:

sed 's#\n# #g' file
sed 's#^$# #g' file

我如何解决它?

答案

sed旨在用于基于行的输入。虽然它可以满足您的需求。


更好的选择是使用tr命令,如下所示:

tr '\n' ' ' < input_filename

或完全删除换行符:

tr -d '\n' < input.txt > output.txt

或您是否拥有 GNU 版本(及其长选项)

tr --delete '\n' < input.txt > output.txt

将此解决方案与 GNU sed

sed ':a;N;$!ba;s/\n/ /g' file

这将循环读取整个文件,然后用空格替换换行符。

说明:

  1. 通过:a创建标签。
  2. 通过N将当前行和下一行添加到模式空间。
  3. 如果我们在最后一行之前,则转到创建的标签$!ba$!表示不要在最后一行上这样做,因为应该有最后一个换行符)。
  4. 最后,替换将每个换行符替换为模式空间上的空格(即整个文件)。

这是与 BSD 和 OS X 的sed兼容的跨平台兼容语法(根据@Benjie comment ):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

如您所见,将sed用于这个其他简单的问题是有问题的。有关更简单和适当的解决方案,请参见此答案

快速回答

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a 创建标签'a'
  2. N 将下一行追加到模式空间
  3. $! 如果不是最后一行 ,则ba 分支(转到)标签 “a”
  4. s/ \ n / regex 替换 换行符/ / 以空格/ g 全局匹配(尽可能多的次数)

sed 将循环执行第 1 步到第 3 步,直到到达最后一行,使所有行都适合 sed 将替换所有 \ n 字符的模式空间


备择方案

sed不同,所有替代方法都无需到达最后一行即可开始该过程

bash

while read line; do printf "%s" "$line "; done < file

perl 一样的 sed速度

perl -p -e 's/\n/ /' file

trsed快,只能用一个字符替换

tr '\n' ' ' < file

使用粘贴tr状速度,只能替换一个字符

paste -s -d ' ' file

使用awk,TR般的速度

awk 1 ORS=' ' file

其他类似“echo $(操作速度很慢,仅适用于小文件,并且需要处理整个文件才能开始处理。


sed FAQ 5.10 的长答案

5.10。为什么我不能使用 \ n 转义来匹配或删除换行符
顺序?为什么我不能使用 \ n 匹配两行或更多行?

\ n 永远不会与行尾的换行符匹配,因为
在将行放置到
模式空间。要将 2 行或更多行插入模式空间,请使用
'N' 命令或类似的命令(例如'H; ...; g;')。

sed 的工作方式如下:sed 一次读取一行,然后将
终止换行符,将剩下的内容放入模式空间
sed 脚本可以解决或更改它,以及模式空间何时
被打印,在标准输出(或文件)后添加换行符。如果
模式空间全部或部分被'd' 或'D' 删除,
在这种情况下添加换行符。因此,类似

sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line

永远都行不通,因为结尾的换行符
将该行放入模式空间。要执行上述任务,
请使用以下脚本之一:

tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line

由于 GNU sed 以外的 sed 版本对
模式缓冲区,这里最好使用 Unix'tr' 实用程序。
如果文件的最后一行包含换行符,则 GNU sed 将添加
该换行符到输出,但删除所有其他换行符,而 tr 将
删除所有换行符。

要匹配两行或更多行的块,有 3 种基本选择:
(1)使用 “N” 命令将下一行添加到模式空间;
(2)至少使用 “H” 命令两次以附加当前行
到保留空间,然后从保留空间检索行
x,g 或 G 或(3)使用地址范围(请参见上文第 3.3 节)
匹配两个指定地址之间的行。

选项(1)和(2)将 \ n 放入模式空间,
可以根据需要进行寻址('s / ABC \ nXYZ / alphabet / g')。一个例子
第 4.13 节中使用 “N” 删除一行行的说明
(“如何删除特定的连续行块?”)。这个
可以通过将 delete 命令更改为某些示例来修改示例
其他,例如 “p”(打印),“i”(插入),“c”(更改),“a”(附加),
或 “s”(替代)。

选择(3)不会将 \ n 放入模式空间,但它确实
匹配一段连续的线,所以可能是您没有
甚至需要 \ n 来查找所需的内容。自 GNU sed 以来
版本 3.02.80 现在支持以下语法:

sed '/start/,+4d'  # to delete "start" plus the next 4 lines,

除了传统的 '/ from here /,/ to there / {...}' 范围
地址,则有可能完全避免使用 \ n。

一个较短的 awk 替代方法:

awk 1 ORS=' '

说明

awk 程序由规则组成,这些规则由条件代码块组成,即:

condition { code-block }

如果省略代码块,则使用默认值: { print $0 } 。因此,将1解释为真实条件,并为每行执行print $0

awk读取输入时,它将根据RS (记录分隔符)的值将其拆分为记录,该值默认为换行符,因此awk默认将按行解析输入。拆分还涉及从输入记录中剥离RS

现在,在打印记录时,将ORS (输出记录分隔符)附加到该记录上,默认情况下还是换行符。因此,通过将ORS更改为空格,所有换行符都更改为空格。

gnu sed 对于空分隔的记录(行)具有-z选项。您可以致电:

sed -z 's/\n/ /g'

Perl版本以您期望的方式工作。

perl -i -p -e 's/\n//' file

正如评论中指出的那样,值得注意的是此编辑已就位。 -i.bak会在替换前为您提供原始文件的备份,以防您的正则表达式不如您想象的那样聪明。

谁需要sed ?这是bash方式:

cat test.txt |  while read line; do echo -n "$line "; done

为了使用 awk 用空格替换所有换行符,而不将整个文件读入内存:

awk '{printf "%s ", $0}' inputfile

如果您想要最后一个换行符:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

您可以使用空格以外的其他字符:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile
tr '\n' ' '

是命令。

简单易用。

三件事。

  1. 绝对不需要tr (或cat等)。 (GNU) sed和(GNU) awk结合使用时,可以完成您需要的任何文本处理的 99.9%。

  2. 流!= 基于行。 ed是基于行的编辑器。 sed不是。有关差异的更多信息,请参见sed 讲座 。大多数人将sed认为是基于行的,因为默认情况下,它对 SIMPLE 匹配的模式匹配不是很贪婪 - 例如,在进行模式搜索并替换一个或两个字符时,默认情况下它仅在第一个字符上替换找到的匹配项(除非全局命令另有指定)。如果是基于行而不是基于 STREAM 的话,甚至没有全局命令,因为它一次只能评估行。尝试运行ed ; 您会注意到其中的区别。如果您想遍历特定行(例如在 for 循环中),则ed非常有用,但是大多数情况下,您只需要sed

  3. 话虽如此,

    sed -e '{:q;N;s/\n/ /g;t q}' file

    在 GNU sed 4.2.1 版本中可以正常工作。上面的命令将所有换行符替换为空格。输入起来很丑陋而且有点麻烦,但是效果很好。可以忽略{} ,因为出于理智的考虑仅将它们包括在内。