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


1370

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

我尝试失败:

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

我如何解决它?


27
tr如果将单个字符替换为单个字符,则仅是该工作的正确工具,而上例显示了用空格替换换行符。因此,在上例中,tr可以工作。
2015年

9
tr之类的工具,因为发问者想用空格替换每个换行符,如他的示例所示。换行符的替换是不可思议的,sed但是可以轻松完成tr。这是一个常见的问题。执行regex替换不是由tr而是通过进行的sed,这将是正确的工具...对于另一个问题。
Mike S

3
“ tr”也可以只删除换行符`tr -d'\ n'`,但是您可能还希望删除返回值以更通用`tr -d'\ 012 \ 015'`。
安东尼

2
警告:“ tr”在Linux和较旧的Solaris计算机(EG sol5.8)之间的字符范围方面作用不同。EG:`tr -d'az'`和`tr -d'[az]'`。为此,我建议您使用没有差别的“ sed”。
安东尼

2
@MikeS感谢您的回答。跟随tr '\012' ' '一个echo。否则,文件中的最后一个换行符也会被删除。tr '\012' ' ' < filename; echo绝招。
伯尼·瑞特

Answers:


1513

将此解决方案与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这个原本简单的问题用于解决问题。有关更简单和适当的解决方案,请参见此答案


45
@Arjan和Masi:OS X使用BSD sed而不是GNU sed,因此两者之间可能存在一些细微(有些不是那么细微)的差异。如果您同时在OS X和* nix机器上工作,这将是一个持续的痛苦。我通常安装GNU的coreutils,并findutils在OS X上,而忽视了BSD版本。
Telemachus

50
:a不是寄存器,它是一个分支标签。它是b命令*(类似于“ goto”)的目标。将其称为寄存器意味着您可以创建存储位置。只有两个“寄存器”。一个称为脚本未使用的“保留空间”,另一个称为“模式空间”。该N命令将输入​​文件的换行符和下一行附加到模式空间。[*您可以有多个标签和b命令。如果您有b未附加标签字符的命令,则该命令会分支到脚本的末尾以读取下一行并再次循环。]
暂停,直到另行通知。

108
您可以通过分别执行命令而不用分号分隔来运行该跨平台(即在Mac OS X上): sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie

74
为什么没有人评论这是什么愚蠢的问题(不是答案本身,而是提出的答案是对一个非常简单的问题的最佳解决方案的程序)。塞德(Sed)看起来像一辆通常可以正常行驶的汽车,但是如果您要开车去附近的特定街道,唯一的方法是用直升机举起汽车。
方舟坤

12
来吧,伙计们-261票赞成一个疯狂的,无法理解的解决方案,该方案行不通?sed是在单个行上进行简单替换的出色工具,对于其他任何操作,只需使用awk。天哪....
埃德莫顿

1711

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


更好的选择是使用以下tr命令:

tr '\n' ' ' < input_filename

或完全删除换行符:

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

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

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

88
Sed是基于行的,因此很难掌握换行符。
亚历山大·格拉迪什

191
sed可以处理“输入”流,但可以用换行符分隔的块来理解。这是一个Unix工具,这意味着它做得很好。一件事是“逐行处理文件”。使其执行其他操作将很困难,并且可能会出现越野车的风险。这个故事的寓意是:选择正确的工具。您的许多问题似乎都采用“我该如何使该工具执行从未打算做的事情?”的形式。这些问题很有趣,但是如果它们在解决一个实际问题的过程中出现,那么您可能做错了。
dmckee ---前主持人小猫,

7
@JBBrown tr是用于构建管道的经常被忽略的宝石。
dmckee ---前主持人小猫,

70
tr很棒,但是您只能用单个字符替换换行符。如果要用字符串替换换行符,则需要使用其他工具
Eddy 2012年

21
@Eddy-我用tr替换了文本中未出现的字符(我使用反引号),然后用sed替换了我想使用的字符串
rjohnston 2013年

493

快速回答

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a 创建标签'a'
  2. N 将下一行追加到模式空间
  3. $! 如果不是最后一行,则ba 分支(转到)标签“ a”
  4. 小号 替代/ \ N / 新线的正则表达式/ / 通过的空间/克 全局匹配(多次它可以)

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


备择方案

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

bash

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

perl的sed的样速度

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

TR,速度比sed的,可以由一个字符替换只

tr '\n' ' ' < file

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

paste -s -d ' ' file

AWKTR般的速度

awk 1 ORS=' ' file

其他替代方法如“ echo $(<file)”速度很慢,仅适用于小文件,需要处理整个文件才能开始处理。


sed FAQ 5.10的长答案

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

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

sed的工作方式如下:sed一次读取一行,剪掉
终止的换行符,将剩下的内容放入
sed脚本可以寻址或更改的模式空间中,并且在
打印模式空间时,在stdout后面添加一个换行符(或到文件)。如果
用'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”命令将当前行追加
到Hold空间,然后
使用x,g或G 从hold空间中检索这些行;或(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。


6
tr是个好主意,而您的总体覆盖范围是一个高质量的答案。
新亚历山大市

1
+1使用(标准实用程序paste...和所有其他功能!
Totor


4
关于此答案的最好的部分是“长答案”准确地解释了命令的工作方式和原因。
pdwalker 2014年

3
这可能是我在stackexchange上阅读的数千个答案中最有用的。我需要跨行匹配多个字符。以前的sed示例没有涉及多行,tr无法处理多个字符匹配。Perl看起来不错,但没有按我预期的那样工作。如果可以的话,我会多次投票给这个答案。
mayypile 2015年

225

一个较短的awk替代方法:

awk 1 ORS=' '

说明

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

condition { code-block }

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

awk读入基于所述值的记录它分裂它输入RS(记录分隔符),默认情况下是一个新行,从而awk将默认解析输入线,明智的。拆分还涉及RS从输入记录中剥离。

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


5
我非常喜欢这个简单的解决方案,该解决方案比其他解决方案更具可读性
Fedir RYKHTIK 2013年

8
如果更有意义,可以将其有效地写为:(awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt添加结束换行符只是为了说明开始/结束);“ 1”的计算结果是true(处理行)和print(打印行)。也可以将条件语句添加到此表达式中,例如,仅在与模式匹配的行上起作用: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
michael

2
您可以更简单地做到这一点: codeawk'ORS =“”'file.txtcode
Udi

不幸的是,当使用这样的awk时,文件中的最后一个换行符也会被删除。参见上面的Patrick Dark答案,关于在像`cat file | echo $ {tr“ \ 012”“”)`可以解决问题。好漂亮
伯尼·瑞特

143

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

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

4
即使输入确实包含空值,也将保留它们(作为记录定界符)。
Toby Speight

6
如果没有空值,这不会加载整个输入吗?在这种情况下,处理数GB的文件可能会崩溃。
罗斯兰

3
@Ruslan,是的,它将加载整个输入。对于千兆字节的文件,此解决方案不是一个好主意。
JJoao

7
认真地讲,这是最好的答案。其他表达方式太扭曲而无法记住。@JJoao可以将其与结合使用-u, --unbuffered。的man法师指出:“从输入文件加载最小量的数据,并且更频繁地刷新输出缓冲器”。
not2qubit

所以。许多。这个。
sjas

85

Perl的版本的作品您预期的方式。

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

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


23
请至少提及,-i没有后缀的文件不会备份-i.bak保护您免受简单,丑陋的错误(例如,忘记键入-p文件并将其清零)的麻烦。
Telemachus

6
@Telemachus:这是一个公平的观点,但是无论哪种方式都可以争论。我没有提到它的主要原因是OP问题中的sed示例没有进行备份,因此在这里似乎是多余的。另一个原因是我从未真正使用过备份功能(实际上我发现自动备份很烦人),所以我总是忘记了它的存在。第三个原因是它使我的命令行延长了四个字符。不管好坏,我都是一个强迫性的极简主义者。我只喜欢简洁。我知道您不同意。我会尽力记住将来要警告有关备份的信息。
ire_and_curses

6
@Ire_and_curses:实际上,您只是因为忽略我而提出了一个该死的好理由。也就是说,您有选择的理由,不管我是否同意选择,我都一定会尊重。我不完全确定为什么,但是最近我一直对这个特殊的东西(-iPerl中的标志没有后缀)感到a然。我相信我很快就会发现其他困扰的东西。:)
Telemachus

不幸的是,通过指定-文件名,此操作不适用于stdin 。有没有办法做到这一点?这是我不用担心修改文件的方法,它使用的是以cat开头的管道。
史蒂文·卢

如果未提供文件名,则@StevenLu Perl将默认从STDIN读取。因此,您可以执行例如perl -i -p -e 's/\n//' < infile > outfile
ire_and_curses,

44

谁需要sed?这里是bash方法:

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

2
Upvote,我通常使用最佳答案,但是当通过/ dev / urandom传递它时,sed直到EOF才打印,并且^ C并非EOF。每当看到换行符时,都会打印此解决方案。正是我需要的!谢谢!
Vasiliy Sharapov

1
那么为什么不呢?echo -n`cat days.txt` 来自这篇文章
Tony

9
@Tony,因为不推荐使用反引号,并且这只猫是多余的;-)使用:echo $(<days.txt)
seumasmac

10
甚至不使用catwhile read line; do echo -n "$line "; done < test.txt。如果子外壳有问题,则可能很有用。
卡洛·坎纳斯

5
echo $(<file)所有空格压缩到一个空格,而不仅仅是换行符:这超出了OP的要求。
glenn jackman

27

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

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

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

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

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

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

END{ print ""}是尾随换行符的较短替代方法。
艾萨克(Isaac)

22
tr '\n' ' ' 

是命令。

简单易用。


14
或者只是tr -d '\n'如果您不想添加空间

21

三件事。

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

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

  3. 话虽如此,

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

    在GNU sed4.2.1版本中可以正常工作。上面的命令将所有换行符替换为空格。输入起来很丑陋而且有点麻烦,但是效果很好。本{}的可以被排除在外,因为他们只是为了理智的原因。


3
作为一个只懂sed基础知识的人,我不得不说这不仅仅是您可以做什么,sed而是要了解正在发生的事情有多么容易。我的工作非常艰辛,sed因此在可以使用它时,我希望使用更简单的命令。
Nate 2014年

使用t q如条件转移这样的作品有类似的图案s/\n / /,而不读取整个文件到内存(加入以空格开头的行)。转换数兆字节的文件时非常方便。
textshell

您链接的文章没有反映您的
发言

这比接受大输入的答案慢了将近800倍。这是因为在越来越大的输入上可以替代每行。
2016年

13

答案:a标签...

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

...在命令行上的freebsd 7.2中不起作用:

(echo foo; echo bar)| sed':a; N; $!ba; s / \ n / / g'
sed:1:“ :: a; N; $!ba; s / \ n / / g”:未使用的标签'a; N; $!ba; s / \ n / / g'
富
酒吧

但是,如果您将sed脚本放入文件中或使用-e“构建” sed脚本,该怎么办...

>(echo foo; echo bar)| sed -e:a -e N -e'$!ba'-e's / \ n / / g'
富吧

要么 ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

也许OS X中的sed很相似。


-e参数系列在使用MKS的Windows上对我有用!谢谢!
JamesG 2011年

12

易于理解的解决方案

我有这个问题。最重要的是,我需要解决方案才能在BSD(Mac OS X)和GNU(Linux和Cygwin)上工作,sed并且tr

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

输出:

foo
bar
baz

(末尾有换行符)

它可以在Linux,OS X和BSD上运行 -即使不支持UTF-8或使用笨拙的终端。

  1. 用于tr将换行符与另一个字符交换。

    NULL\000\x00)很不错,因为它不需要UTF-8支持,也不太可能使用。

  2. 使用sed匹配NULL

  3. 使用tr以交换回额外的新行,如果你需要他们


1
关于术语的微妙注释:该字符\000通常被称为NUL(一个L),NULL通常在谈论零指针时使用(在C / C ++中)。
平方英尺2016年


9

我不是专家,但是我想sed您首先需要将下一行添加到模式空间中,使用“ N”进行bij 。在sed&awk(Dale Dougherty和Arnold Robbins; O'Reilly 1997;预览的第107页)的“高级sed命令”中的“多行模式空间”部分中:

multiline Next(N)命令通过读取输入的新行并将其附加到模式空间的内容来创建多行模式空间。模式空间的原始内容和新输入行用换行符分隔。嵌入的换行符可以通过转义序列“ \ n”在模式中进行匹配。在多行模式空间中,元字符“ ^”与模式空间的第一个字符匹配,而不与任何嵌入的换行符之后的字符匹配。同样,“ $”仅匹配模式空间中的最后一个换行符,而不匹配任何嵌入的换行符。执行Next命令后,控制权随后传递给脚本中的后续命令。

来自man sed

[2addr] N

使用嵌入的换行符将输入的下一行追加到模式空间,以将附加的材料与原始内容分开。请注意,当前行号会更改。

用它来搜索(多个)格式错误的日志文件,其中搜索字符串可能在“孤立的”下一行中找到。


7

我使用了一种混合方法来解决换行问题,方法是使用tr将新行替换为制表符,然后将制表符替换为所需的任何内容。在这种情况下,为“
”,因为我试图生成HTML中断。

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

6

为了响应上述“ tr”解决方案,在Windows上(可能使用tr的Gnuwin32版本),建议的解决方案:

tr '\n' ' ' < input

对我不起作用,由于某种原因,它要么是错误,要么实际上是替换\ nw /。

使用tr的另一个功能,“删除”选项-d确实可以工作:

tr -d '\n' < input

或'\ r \ n'而不是'\ n'


3
在Windows上,您可能需要使用tr "\n" " " < input。Windows Shell(cmd.exe)不会将撇号当作引号字符。
基思·汤普森

不,在Windows 10 Ubuntu子系统中,您需要使用tr "\n\r" " " < input.txt > output.txt
user1491819

在Windows 10上使用Gnuwin32:可以使用cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt。或者,代替Gnuwin32,使用Gow(在Windows上为Gnu),github.com/bmatzelle/gow/wiki
Alchemistmatt

5

防弹解决方案。二进制数据安全且符合POSIX,但速度较慢。

POSIX sed 需要根据 POSIX文本文件POSIX行 定义进行输入,因此不允许NULL字节和太长的行,并且每行必须以换行符结尾(包括最后一行)。这使得很难使用sed处理任意输入数据。

以下解决方案避免使用sed,而是将输入字节转换为八进制代码,然后再次转换为字节,但截取八进制代码012(换行符)并输出替换字符串来代替它。据我所知,该解决方案符合POSIX,因此它应可在多种平台上运行。

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

POSIX参考文档: shshell命令语言odtrgrepread[printf

这两个read[printf在至少bash的内置插件,但很可能不是由POSIX保证,所以在一些平台上它可能是每一个输入字节将启动一个或多个新的进程,这将慢下来。即使在bash中,此解决方案也只能达到约50 kB / s,因此它不适用于大型文件。

在Ubuntu(重击,破折号和busybox),FreeBSD和OpenBSD上进行了测试。


5

在某些情况下,您可以更改RS为其他字符串或字符。这样,\ n可用于sub / gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

Shell脚本的强大功能在于,如果您不知道如何以一种方式进行操作,则可以以另一种方式进行操作。很多时候,与为一个简单的问题提供复杂的解决方案相比,您需要考虑的事情更多。

关于gawk速度很慢...并将文件读入内存的情况,我不知道这一点,但是对我而言,gawk似乎只处理一行,并且速度非常快(不如其他一些那么快) ,但是编写和测试的时间也很重要)。

我处理MB甚至GB的数据,而我发现的唯一限制是行大小。


5

如果您很不幸不得不处理Windows行尾,则需要删除\r\n

tr '[\r\n]' ' ' < $input > $output

这取代[了空间,并\r有空间,\n有空间,]有空间。tr -d '\r\n' <file会删除任何\r\n字符,但这也不是要询问的内容。tr -d '\r' <file会删除任何可能更有用的\r字符(无论它们是否与相邻\n),并且很可能会纠正OP的需要(仍然假设您tr理解此反斜杠符号)。
Tripleee

4

您可以使用xargs- \n默认情况下它将替换为空格。

但是,如果您输入的任何情况都存在,则会出现问题unterminated quote,例如,如果给定行上的引号不匹配。


xargs还可以很好地处理最后一行:
AAAfarmclub

4

使用允许\ n查找和替换

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

记号笔

成为

#标记注释

记号笔


4

为什么没有找到简单的解决方案awk

awk '{printf $0}' file

printf 如果要用空格或其他分隔原始行,将打印每行而不包含换行符:

awk '{printf $0 " "}' file

echo "1\n2\n3" | awk '{printf $0}',这对我有用。@ edi9999
Itachi

您是对不起,我忘记了fprintf
edi9999

这是在Windows的git bash中对我有用的唯一方法
柏拉图

3

在Mac OS X上(使用FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta


3

使用Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"

2
如果将外面的单引号更改为引号,则不需要转义引号和美元符号。字母“ o”通常被认为是变量名称的错误选择,因为它可能与数字“ 0”混淆。您也不需要初始化变量,它默认为空字符串。但是,如果您不希望有多余的开头空间:awk '{s = s sp $0; sp = " "} END {print s}'。但是,请参见我的答案以获取一种使用awk而不将整个文件读入内存的方法。
暂停,直到另行通知。

检查托尔的答案吧。相对于此方法,它可以更有效,更易读且更胜一筹(即使可以使用)!
mschilli 2013年

杜德,我明白了。无需在我的脸上擦拭它:-)无论如何,雷神的答案在页面上方(是正确的),那么您在乎什么呢?
kralyk 2013年

3

我特别喜欢的解决方案是将所有文件追加到保留空间中,并在文件末尾替换所有换行符:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

但是,有人说我在某些sed实现中保留空间可能是有限的。


1
在您的答案中用空字符串替换将掩盖一个事实,即始终使用H附加到保留空间意味着保留空间将以换行符开头。为避免这种情况,您需要使用1h;2,$H;${x;s/\n/x/g;p}
Jeff

3

用任何字符串替换换行符,并替换最后一个换行符

tr解决方案只能替换为单个字符,而纯sed解决方案不能替换输入的最后换行符。以下解决方案解决了这些问题,并且对于二进制数据(即使使用UTF-8语言环境)似乎也很安全:

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

结果:

1<br>2<br>3<br>

这很糟糕,因为它将在包含以下内容的任何输入上产生不想要的输出@
Steven Lu

@StevenLu:否,@在输入中可以。它逃脱了%a再回来。但是,该解决方案可能并不完全符合POSIX(不允许使用NULL字节,因此对二进制数据不利,并且所有行都必须以换行符结尾,因此tr输出实际上不是有效的)。
哈康A. Hjortland

啊。我看你已经解决了。Kinda对于应该是简单的操作却是很好的工作感到费解。
史蒂文·卢

3

的sed,介绍后,“正常”的替代新线。首先,它会修剪换行符,然后根据您的指示进行处理,然后引入一个换行符。

使用sed,您可以为每条输入线在修剪后用您选择的字符串替换行的“结尾”(而不是换行char)。但是,sed将输出不同的行。例如,假设您想将“行尾”替换为“ ===“(比用单个空格替换更通用):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

要用字符串替换换行字符,您可以使用前面提到的tr低效率地将换行字符替换为“特殊字符”,然后使用sed将所需的特殊字符替换为所需的字符串。

例如:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$

3

您也可以使用此方法

sed 'x;G;1!h;s/\n/ /g;$!d'

说明

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
      last line.

流程:
从输入中获得第一行后,进行交换,因此1进入保留空间,\ n进入模式空间,然后将保留空间附加到模式空间,然后执行替换并删除模式空间。
在第二行交换期间,2进入保留空间,1进入模式空间,然后G将保留空间附加到模式空间,然后h将模式复制到该模式空间,进行替换并删除。继续此操作,直到达到eof,然后打印出准确的结果。


但是,请注意会echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'导致XY
诡异的

3

另一种GNU sed方法,几乎​​与Zsolt Botykai的答案相同,但是使用sed的是较少使用的ytransliterate)命令,该命令节省了一个字节的代码(尾随g):

sed ':a;N;$!ba;y/\n/ /'

人们希望y运行速度比快s(也许在tr速度上要快20倍),但是在GNU sed v4.2.2 y中比慢4%s


更便携的BSD sed版本:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'

2
使用BSD sed y大约快15%。有关工作示例,请参见此答案
2016年

同样,使用BSD sed命令需要在标签后终止,这是可行sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'的方法。
ghoti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.