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

如何使用sed命令replace换行符( \n )?

我尝试失败:

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

我该如何解决?

在GNU sed使用这个解决scheme:

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

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

说明:

  1. 通过:a创build标签:a
  2. 通过N追加当前行和下一行到模式空间。
  3. 如果我们在最后一行之前,分支到创build的标签$!ba$!意味着不要在最后一行执行,因为应该有最后一行)。
  4. 最后,replace用模式空间(这是整个文件)上的空格replace每一个换行符。

这里是与BSD和OS X的sed (根据@Benjie评论 )一起使用的跨平台兼容语法:

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

tr代替?

 tr '\n' ' ' < input_filename 

或者完全删除换行符:

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

或者如果你有GNU版本(有很长的选项)

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

快速回答:

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

sed将循环执行第1步到第3步,直到到达最后一行,将所有行放在模式空间中,其中sed将replace所有\ n个字符


替代品

sed不同的是,所有的select都不需要到达最后一行来开始这个过程

bash ,慢

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

perlsed- like的速度

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

tr ,比sed快,只能用一个字符replace

 tr '\n' ' ' < file 

tr样速度,只能由一个字符replace

 paste -s -d ' ' file 

awktr- like的速度

 awk 1 ORS=' ' file 

其他的select像“echo $(<file)”是很慢的,只适用于小文件,需要处理整个文件来开始这个过程。


从sed的 长答案 常见问题5.10 :

5.10。 为什么我不能使用\ n转义匹配或删除换行符
序列? 为什么我不能匹配2行或更多行使用\ 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会
删除所有换行符。

要匹配两行或更多行的块,有三个基本的select:
(1)使用'N'命令将下一行添加到模式空间;
(2)使用“H”命令至less两次追加当前行
到保留空间,然后从保存空间中检索行
与x,g或者G; 或者(3)使用地址范围(参见上面的3.3节)
匹配两个指定地址之间的行。

select(1)和(2)会将\ n放入模式空间中
可以根据需要进行处理('s / ABC \ nXYZ / alphabet / g')。 一个例子
使用'N'删除一行代码块出现在4.13节
(“如何删除特定连续行的块?”)。 这个
可以通过将delete命令更改为某些内容来修改示例
其他,如'p'(print),'i'(插入),'c'(更改),'a'(追加),
或's'(替代)。

select(3)不会将\ n放入模式空间,但它确实如此
匹配一个连续的线块,所以可能是你不这样做
甚至需要\ nfind你要找的东西。 自从GNU sed
版本3.02.80现在支持这个语法:

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

除了传统的“/ from here /,/ to there / {…}”范围之外
地址,可能完全避免使用\ n。

一个更短的awkselect:

 awk 1 ORS=' ' 

说明

awk程序由包含条件代码块的规则组成,即:

 condition { code-block } 

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

awk读取input时,它将根据RS (logging分隔符)的值将其分割为logging,默认情况下这是一个换行符,因此awk默认将按行逐行parsinginput。 拆分还涉及从inputlogging中剥离RS

现在,当打印logging时, ORS (输出logging分隔符)被追加到它(默认再次是一个换行符)。 所以通过改变ORS到一个空格,所有换行符都被改变成空格。

Perl版本按照您的预期工作。

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

正如评论中指出的那样,值得注意的是,这个编辑已经到位。 -i.bak会在replace之前为您提供原始文件的备份,以防您的正则expression式不如您想象的那么聪明。

gnu sed有一个选项-z用于空分离的logging(行)。 你可以打电话给:

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

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

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

为了用awkreplace所有带空格的换行符,而不将整个文件读入内存:

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

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

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

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

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

三件事。

  1. tr (或cat等)是绝对不需要的。 (GNU) sed和(GNU) awk结合起来,可以做99.9%的任何你需要的文本处理。

  2. stream!=基于行。 ed是一个基于行的编辑器。 sed不是。 有关差异的更多信息,请参见sed讲座 。 大多数人把sed混淆为基于行的,因为默认情况下,对于SIMPLE匹配的模式匹配不是非常贪婪 – 例如,当进行模式search和replace一个或两个字符时,默认情况下只会replace第一个匹配它发现(除非由全局命令另外指定)。 如果它是基于行的而不是基于STREAM的,那么甚至不会有全局的命令,因为它一次只评估一行。 尝试运行ed ; 你会注意到不同之处。 ed是非常有用的,如果你想迭代特定的行(例如在for循环),但大多数时候你只是想sed

  3. 话虽如此,

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

    在GNU sed版本4.2.1中工作得很好。 上述命令将用空格replace所有换行符。 这很丑陋,input起来很麻烦,但是工作得很好。 {}可以省略,因为它们只是出于理智的原因而被包括在内。

 tr '\n' ' ' 

是命令。

简单易用。

答案是:一个标签…

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

…在命令行的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'
 FOO
酒吧

但是,如果你把sed脚本放在一个文件中,或者使用-e来“build立”sed脚本…

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

要么 …

 > cat > x.sed << eof :a N $!ba s/\n/ /g eof > (echo foo; echo bar) | sed -f x.sed foo bar 

也许OS X的sed是相似的。

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

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

man sed

[2addr] n的

将下一行的input附加到模式空间,使用embedded的换行符将附加的材料从原始内容中分离出来。 请注意,当前行号会更改。

我用它来search(多个)格式不好的日志文件,其中searchstring可能在“孤立的”下一行中find。

你可以使用xargs :

 seq 10 | xargs 

要么

 seq 10 | xargs echo -n 

为了响应上面的“tr”解决scheme,在Windows上(可能使用tr的Gnuwin32版本),build议的解决scheme是:

 tr '\n' ' ' < input 

不是为我工作,它会错误或实际上取代\ nw /''出于某种原因。

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

 tr -d '\n' < input 

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

易于理解的解决scheme

我有这个问题。 踢球者是我需要的解决scheme在BSD(Mac OS X)和GNU(Linux和Cygwin ) sedtr

 $ 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支持,也可以使用蹩脚的terminal。

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

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

  2. 使用sed来匹配NULL

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

我用一个混合的方法来解决换行符的问题,用tr来replace标签中的换行符,然后用我想要的replace标签。 在这种情况下, ”
“因为我试图生成HTML中断。

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

在某些情况下,也许你可以改变RS到其他string或字符。 这样,\ n可用于子/ gsub:

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

shell脚本的强大之处在于,如果你不知道如何做到这一点,你可以用另一种方式来完成。 很多时候,你需要考虑更多的事情,而不是在一个简单的问题上做一个复杂的解决scheme。

对于gawk慢的东西,把这个文件读入内存,我不知道这个,但是对于我来说,gawk似乎在一行工作,速度非常快(不像其他一些,但编写和testing的时间也是很重要的)。

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

您可以使用xargs – 默认情况下,它将用空格replace\n

但是,如果您的input有任何unterminated quote ,例如,如果给定行中的报价标志不匹配,则会出现问题。

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

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

以下解决scheme避免了sed,而是将input字节转换为八进制代码,然后再转换为字节,但截取了八进制代码012(换行符),并输出replacestring代替它。 据我所知,解决scheme是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参考文档: sh , shell命令语言 , od , tr , grep , read , [ , printf 。

read[printf都至less在bash中是内置的,但POSIX可能无法保证这一点,所以在某些平台上,每个input字节可能会启动一个或多个新进程,这会降低速度。 即使在bash中,这个解决scheme也只能达到50kB / s,所以不适合大文件。

在Ubuntu上testing(bash,dash和busybox),FreeBSD和OpenBSD。

在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 

使用Awk:

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

我特别喜欢的解决scheme是在保存空间中追加所有文件,并在文件末尾replace所有换行符:

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

然而,有人说我在一些sed实现中占用空间可能是有限的。

用任何stringreplace换行符,并replace最后一个换行符

纯粹的tr解决scheme只能用一个字符replace,纯sed解决scheme不会取代最后一个换行符。 以下解决scheme解决了这些问题,并且对于二进制数据(即使使用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> 

在“正常”替代之后引入新线是sed 。 首先,它修剪新的字符,然后根据你的指示进行处理,然后引入新的字符。

使用sed,你可以用一个你自己select的stringreplace每个input行的一行(不是换行符)的“结束” 但是, sed会输出不同的行。 例如,假设你想用“===”replace“end of line”(比一个空格replace更普遍):

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

要用stringreplace换行符,可以用效率低下的tr来replace换行符,用“特殊字符”代替,然后使用sed用你想要的stringreplace那个特殊的字符。

例如:

 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~$ 

@OP,如果要replace文件中的换行符,可以使用dos2unix(或unix2dox)

 dos2unix yourfile yourfile 

删除空行:

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

你也可以使用这个方法

 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. 

stream:
当第一行从input获得时,交换成立,所以1进入空间,\ n进入模式空间,然后将保持空间附加到模式空间,然后进行replace,删除模式空间。
在第二行进行交换时,2进行保存空间,1进入模式空间,然后G将保留空间追加到模式空间中,然后将模式拷贝到模式空间中,并replace被删除。 这个操作一直持续到eof到达,然后打印确切的结果。

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

This does not work for huge files (buffer limit), but it is very efficient if there is enough memory to hold the file. (Correction H -> 1h;1!H after the good remark of @hilojack )

Another version that change new line while reading (more cpu, less memory)

  sed ':loop $! N s/\n/ / t loop' YourFile 

Another sed method, almost the same as Zsolt Botykai 's answer , but this uses sed 's less-frequently used y ( transliterate ) command, which saves one byte of code (the trailing 'g'):

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

One would hope y would run faster than s , (perhaps at tr speeds, 20x faster), but in GNU sed v4.2.2 y is about 4% slower than s .

You can also use the Standard Text Editor :

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

Note: this saves the result back to file .

As with sed , this solution suffers from having to load the whole file into memory first.