我怎么能替换每个换行符(\n)与一个空格使用se?

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

我尝试失败:

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

我该怎么修?

2106269 次浏览

sed旨在用于基于行的输入。虽然它可以做你需要的事情。


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

tr '\n' ' ' < input_filename

或完全删除换行符:

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

或者如果您有GNU版本(及其长选项)

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

perl版本按照您预期的方式工作。

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

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

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

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

man sed

[2addr]N

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

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

将此解决方案与GNUsed一起使用:

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

这将在循环中读取整个文件(':a;N;$!ba),然后用空格(s/\n/ /g)替换换行符。如果需要,可以简单地附加其他替换。

说明:

  1. sed首先将第一行不包括换行符读取到模式空间中。
  2. 通过:a创建标签。
  3. 通过N将换行符和下一行附加到模式空间。
  4. 如果我们在最后一行之前,分支到创建的标签$!ba$!意味着不在最后一行执行。这是避免再次执行N所必需的,如果没有更多输入,这将终止脚本!)。
  5. 最后,替换用模式空间(即整个文件)上的空格替换每个换行符。

这是跨平台兼容的语法,适用于BSD和OS X的sed(根据@本杰评论):

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

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

@OP,如果你想替换文件中的换行符,你可以使用dos 2unix(或unix2dox)

dos2unix yourfile yourfile

答案是:一个标签…

我怎么能替换换行符(\n)使用Sed?

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

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'foobar

但是,如果您将ses脚本放在文件中或使用-e来“构建”ses脚本…

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

或者…

> cat > x.sed << eof:aN$!bas/\n/ /geof
> (echo foo; echo bar) | sed -f x.sedfoo bar

也许OS X中的Sed类似。

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

# replace each newline with a spaceprintf "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

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

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

试试这个:

echo "a,b"|sed 's/,/\r\n/'

针对上面的“tr”解决方案,在Windows上(可能使用Gnuwin32版本的tr),建议的解决方案:

tr '\n' ' ' < input

不适合我,它要么出错,要么出于某种原因实际上替换了\n w/"。

使用tr的另一个功能,“删除”选项-d确实有效:

tr -d '\n' < input

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

三件事。

  1. (GNU)sed和(GNU)awk结合在一起,可以完成99.9%的文本处理。

  2. 流!=基于行的。ed是基于行的编辑器。sed不是。请参阅sed讲座了解更多关于区别的信息。大多数人将sed混淆为基于行的,因为默认情况下,它对简单匹配的模式匹配不是很贪婪——例如,当进行模式搜索并用一两个字符替换时,默认情况下它只替换它找到的第一个匹配项(除非全局命令另有指定)。如果它是基于行的,而不是基于STREAM的,甚至不会有全局命令,因为它一次只会评估行。如果你想遍历特定的行(例如在for循环中),ed非常有用,但大多数情况下你只需要sed

  3. 话虽如此,

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

    在GNUsed版本4.2.1中运行得很好。上面的命令将用空格替换所有换行符。它很丑陋,输入有点麻烦,但它运行得很好。{}可以省略,因为它们只包含在理智的原因中。

删除空行:

sed -n "s/^$//;t;p;"

使用awk:

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

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

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

然而,有人告诉我,在一些Sed实现中,保持空间可能是有限的。

这是sed没有缓冲区(适合实时输出)。
示例:在超文本标记语言中将\n替换为<br/>中断

echo -e "1\n2\n3" | sed 's/.*$/&<br\/>/'

这真的很简单……当我找到解决方案时,我真的很生气。只有一个后斜杠不见了。就是这样:

sed -i "s/\\\\\n//g" filename

快速回答

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a创建一个标签'a'
  2. N将下一行附加到模式空间
  3. $!如果不是最后一行ba分支(转到)标签'a'
  4. <的trong>的替代/\n/新线的正则表达式//由空间/g全球匹配(尽可能多次)

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


替代品

ed不同的是,所有替代方案都不需要到达最后一行即可开始该过程

bash,慢

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

perled的速度

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

孩子们ed快,只能用一个字符替换

tr '\n' ' ' < file

孩子们类似的速度,只能替换一个字符

paste -s -d ' ' file

awk孩子们的速度

awk 1 ORS=' ' file

其他替代方案(如回声$()很慢,仅适用于小文件,并且需要处理整个文件才能开始该过程。


SED FAQ 5.10的长答案

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

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

Sed是这样工作的:Sed一次读取一行,砍掉
终止换行符,将剩余的内容放入模式空间,其中
Sed脚本可以寻址或更改它,并且当模式空间
打印,将换行符附加到标准输出(或文件)。如果
使用'd'或'D'完全或部分删除模式空间,
在这种情况下,换行符是没有添加的。因此,像

这样的脚本
  sed 's/\n//' file       # to delete newlines from each linesed 's/\n/foo\n/' file  # to add a word to the end of each line

永远不会工作,因为尾随的换行符被删除之前
该行被放入模式空间。要执行上述任务,
使用以下脚本之一:

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

因为除了GNU ses之外的se版本对
的大小有限制模式缓冲区,Unix'tr'实用程序在这里是首选的。
如果文件的最后一行包含换行符,GNU ses将添加
该换行符到输出,但删除所有其他行,而tr将
删除所有换行符。

要匹配包含两行或多行的块,有3个基本选择:
(1)使用'N'命令将Next行添加到模式空间;
(2)至少两次使用'H'命令来附加当前行
到保持空间,然后从保持空间
中检索行使用x、g或G;或(3)使用地址范围(见上文第3.3节)
以匹配两个指定地址之间的行。

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

选择(3)不会将\n放入模式空间,但它确实
匹配连续行的块,因此可能不
甚至需要\n来找到你要找的东西。因为GNU ses
版本3.02.80现在支持此语法:

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

除了传统的'/from here/,/to that/{…}'范围

,则可以完全避免使用\n。

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

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

shell脚本的强大之处在于,如果你不知道如何用一种方式来做,你可以用另一种方式来做。很多时候,你需要考虑的事情比对一个简单问题做出复杂的解决方案还要多。

关于gawk很慢……并将文件读入内存的事情,我不知道这一点,但对我来说,gawk似乎一次只能使用一行,而且非常非常快(不像其他一些行那么快,但写入和测试的时间也很重要)。

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

简单易懂的解决方案

我遇到了这个问题。问题是我需要解决方案来处理BSD(Mac OS X)和GNU(Linux和Cygwinsedtr

$ echo 'foobarbaz

foo2bar2baz2' \| tr '\n' '\000' \| sed 's:\x00\x00.*:\n:g' \| tr '\000' '\n'

输出:

foobarbaz

(有尾随换行符)

它适用于Linux、OS X和BSD-即使没有UTF-8支持或使用蹩脚的终端。

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

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

  2. 使用sed匹配NULL

  3. 如果需要,使用tr交换回额外的换行符

我使用了一种混合方法来绕过换行符,使用tr将换行符替换为制表符,然后将制表符替换为我想要的任何内容。在这种情况下,“
”因为我试图生成超文本标记语言中断。

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

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

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

如果你想要一个最终的换行符:

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

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

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

以下内容比大多数答案简单得多。而且,它正在工作:

echo `sed -e 's/$/\ |\ /g' file`

在ed替换部分中,键入反斜杠,按回车键进入第二行,然后以 /g'结束:

sed 's/>/\/g'
[root@localhost ~]# echo "1st</first>2nd</second>3rd</third>" | sed 's/>/\> /g'1st</first2nd</second3rd</third
[root@localhost ~]#

更短的awk替代方案:

awk 1 ORS=' '

补充说明

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

condition { code-block }

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

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

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

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

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>

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

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

sed '1h;1!H;$!dx;s/\n/ /g' YourFile

这对大文件(缓冲区限制)不起作用,但如果有足够的内存来保存文件,它会非常有效。(更正H->1h;1!H后的好评论@HiloJack)

另一个在读取时更改新行的版本(更多cpu,更少内存)

 sed ':loop$! Ns/\n/ /t loop' YourFile
tr '\n' ' '

这是命令。

简单易用。

在“正常”替换之后引入新行的是ed。首先,它修剪新行字符,然后根据您的说明进行处理,然后引入新行。

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

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

要用字符串替换换行符char,您可以低效地使用孩子们,如前所述,用“特殊字符”替换换行符char,然后使用ed用您想要的字符串替换该特殊字符。

例如:

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

防弹解决方案。二进制数据安全和POSIX兼容,但速度慢。

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

下面的解决方案避免了ses,而是将输入字节转换为八进制代码,然后再次转换为字节,但拦截八进制代码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命令语言od孩子们grep阅读[printf.

read[printf至少都内置在bash中,但POSIX可能无法保证这一点,因此在某些平台上,每个输入字节可能会启动一个或多个新进程,这会减慢速度。即使在bash中,该解决方案也只能达到约50 kB/s,因此不适合大文件。

在Ubuntu(bash、dash和busybox)、FreeBSD和OpenBSD上测试。

您可以使用xargs

seq 10 | xargs

seq 10 | xargs echo -n

您也可以使用此方法:

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 isavailable in pattern space.$!d - Clear the pattern space every time before getting the next line until thethe last line.

流量

当第一行从输入中获取时,进行交换,因此1进入保持空间,\n进入模式空间,将保持空间附加到模式空间,并执行替换并删除模式空间。

在第二行中,进行交换,2进入保持空间,1进入模式空间,G将保持空间附加到模式空间中,h将模式复制到它,进行替换并删除。此操作继续进行,直到达到EOF并打印出确切的结果。

GNU ses有一个选项-z,用于空分隔的记录(行)。您可以调用:

sed -z 's/\n/ /g'
sed -i ':a;N;$!ba;s/\n/,/g' test.txt
tr "\n" <file name>

另一个GNUsed方法,几乎与佐尔特·博提凯的回答相同,但这使用了sed不太常用的y音译)命令,它节省了一个字节的代码(尾随g):

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

人们希望ys跑得快(也许在tr的速度下,快20倍),但在GNU ses v4.2.2中,ys慢6倍。


更便携的BSDsed版本:

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

您也可以使用标准文本编辑器

printf '%s\n' '%s/$/ /' '%j' 'w' | ed -s file

注意:这将结果保存回file

与这里的大多数sed答案一样,这个解决方案必须首先将整个文件加载到内存中。

大多数以前的sed命令示例在我的Unix框中对我不起作用,并给我错误消息:

Label too long: {:q;N;s/\n/ /g;t q}

这适用于所有Unix/Linux环境:

line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt)echo $line |sed 's/ //g' > sortedoutput.txt

第一行将从文件yoursourcefile.txt中删除所有新行并生成一行。第二个sed命令将删除其中的所有空格。

这可能对你有用(GNU Sed):

sed 'H;$!d;x;:a;s/^((.).*)\2/\1 /;ta;s/.//' file

H命令在模式空间中添加一个换行符,然后将结果附加到保留空间。se的正常流程是从每行中删除以下换行符,因此这将在保留空间的开头引入一个换行符并复制文件的其余部分。一旦文件被粗略地放入保留空间,将保留空间与模式空间交换,然后使用模式匹配将所有原始换行符替换为空格。最后,删除引入的换行符。

这样做的好处是永远不会在ses命令中实际输入换行符字符串。

备选案文:

sed 'H;$!d;x;y/\n/ /;s/.//' file

或:

sed 'H;1h;$!d;x;y/\n/ /' file

查找和替换使用允许\n

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

标记

成为

#标记注释

标记

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

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

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

awk '{printf $0}' file

如果您想用空格或其他方式分隔原始行,printf将打印不带换行符的每一行:

awk '{printf $0 " "}' file

另一种选择:

tr -s "[:space:]" " " < filename > filename2 && mv filename2 filename

其中tr -s表示:

-s,--crick-重复替换重复字符的每个序列在最后指定的SET中列出的,该字符的一次出现

这使用单个空格替换文件中的所有空白序列,将结果写入新文件,然后将新文件重命名为原始名称。

cat file | xargs

为了完整起见