如何使用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换行符。
说明:
- 通过
:a
创build标签:a
。 - 通过
N
追加当前行和下一行到模式空间。 - 如果我们在最后一行之前,分支到创build的标签
$!ba
($!
意味着不要在最后一行执行,因为应该有最后一行)。 - 最后,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
- : 创build一个标签“a”
- N 将下一行添加到模式空间
- $! 如果不是最后一行 , ba 分支(转到)标签“a”
- / n / 正则expression式换行 , / / 空格 , / g 全局匹配(尽可能多的次数)
sed将循环执行第1步到第3步,直到到达最后一行,将所有行放在模式空间中,其中sed将replace所有\ n个字符
替代品 :
与sed不同的是,所有的select都不需要到达最后一行来开始这个过程
与bash ,慢
while read line; do printf "%s" "$line "; done < file
用perl , sed- like的速度
perl -p -e 's/\n/ /' file
用tr ,比sed快,只能用一个字符replace
tr '\n' ' ' < file
与贴 , tr样速度,只能由一个字符replace
paste -s -d ' ' file
用awk , tr- 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
三件事。
-
tr
(或cat
等)是绝对不需要的。 (GNU)sed
和(GNU)awk
结合起来,可以做99.9%的任何你需要的文本处理。 -
stream!=基于行。
ed
是一个基于行的编辑器。sed
不是。 有关差异的更多信息,请参见sed讲座 。 大多数人把sed
混淆为基于行的,因为默认情况下,对于SIMPLE匹配的模式匹配不是非常贪婪 – 例如,当进行模式search和replace一个或两个字符时,默认情况下只会replace第一个匹配它发现(除非由全局命令另外指定)。 如果它是基于行的而不是基于STREAM的,那么甚至不会有全局的命令,因为它一次只评估一行。 尝试运行ed
; 你会注意到不同之处。ed
是非常有用的,如果你想迭代特定的行(例如在for循环),但大多数时候你只是想sed
。 -
话虽如此,
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 ) 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支持,也可以使用蹩脚的terminal。
-
使用
tr
将换行换成另一个字符。NULL
(\000
或\x00
)很好,因为它不需要UTF-8支持,而且不太可能被使用。 -
使用
sed
来匹配NULL
-
如果你需要使用
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.