如何使用sed命令替换换行符(
?
我尝试失败:
1 2 3
| sed 's#
# #g' file
sed 's#^$# #g' file |
我该怎么修?
- 如果将单个字符替换为单个字符,则tr只是该作业的正确工具,而上面的示例显示用空格替换换行符。所以在上面的例子中,tr可以工作。但以后会受到限制。
- @以东王1号〔1〕的混乱。使用sed将新分隔符附加到每行的末尾,然后使用tr删除新行。比sed唯一的方法更不神秘。
- tr在正确的工作工具中,因为提问者希望用空格替换每一个换行符,如他的示例所示。对于sed来说,换行是一个独特的奥秘,但很容易由tr完成。这是一个常见的问题。执行regex替换不是由tr完成,而是由sed完成,这将是正确的工具…换一个问题。
- "tr"也可以删除换行符"tr-d''',但是您也可以删除返回值,使其更通用"tr-d' 12 15''。
- 警告:"tr"在Linux和旧版Solaris计算机(如sol5.8)之间的字符范围方面的作用不同。例如:'tr-d'a-z'和'tr-d'[a-z]`。为此,我建议你使用"sed",这没有什么区别。
- @Mikes感谢你的回答。跟随tr '\012' ' '和echo。否则,文件中的最后一个换行符也将被删除。tr '\012' ' ' < filename; echo做了这个把戏。
- @Berniereiter可以通过调用echo命令子shell:echo $(tr"\012""")中的tr命令巧妙地缓解最后的换行问题。
- @Patrick Dark cat text.txt | echo $(tr"\012""")酷:—)谢谢你的提示!
用tr代替?
1 2
| tr '
' ' ' < input_filename |
或者完全删除换行符:
1 2
| tr -d '
' < input.txt > output.txt |
号
或者如果您有GNU版本(有长选项)
1 2
| tr --delete '
' < input.txt > output.txt |
- 我不明白为什么塞德做不到。请澄清使用不同的工具。
- SED是基于行的,因此很难掌握新行。
- 亚历山大:"流编辑器"是指基于行的吗?也许,这个名字让人困惑。
- SED在"输入流"上工作,但它以换行分隔的块来理解它。它是一个Unix工具,这意味着它可以很好地完成一件事情。一件事是"在文件行上工作"。让它做些别的事情是很困难的,而且有被马车撞到的危险。故事的寓意是:选择正确的工具。你提出的许多问题似乎都是这样的:"我怎样才能让这个工具做一些它从未打算做的事情?"这些问题很有趣,但如果它们是在解决真正的问题的过程中出现的,那么你很可能是做错了。
- 对于这个问题,带有"tr"的语法似乎非常简单,比sed更容易理解。
- 这个答案对我将一个(日志)文件的三行连续组合成一行非常有帮助,通过以下过程:grep--在上下文3(模式)(文件)tr'''sed-e's/--//g'。
- @J.B.Brown tr是建造管道时经常被忽视的宝石。
- tr很好,但只能用单个字符替换换行符。如果要用字符串替换换行符,则需要使用其他工具
- @Eddy-我用tr替换新行,用一个没有出现在文本中的字符(我使用了反勾号),然后用我想要使用的字符串替换反勾号。
- 我很高兴我得到了博蒂凯的回答。StackOverflow还用于派生新的解决方案。要删除XML标记之间的空格:cat input.svg | sed -e ':a;N;$!ba;s/>\W*</></g' > result.svg才有效。你会怎么做?(一行一行杀死小猫!)
- 比SED更容易搜索和替换。
- 不适用于彩色输出。我在这个问答中尝试了所有方法,但当输出为ANSI彩色时,没有任何效果。在Ubuntu 13.04上测试
- @Elgalu-这可能是因为颜色(字符)干扰了搜索/替换模式。我使用以下别名在需要时从流中删除颜色:alias noc='sed -r"s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"'。
- 这是最好的解决方案,尤其是sed和tr的组合:tr '
' '?' | sed 's/?/ .. /g'。
- 或者删除新行:tr -d '
' < input_filename。
- 这很好…但不是很一般的建议。如果我正在做一个regex,我想在那里有一个新的线路,那么tr对我来说毫无价值……
- @Jheriko,OP要求更换新品。这是否仍然描述了你的情况("做一个regex"-无论你说"做"是什么意思)?
- 我的意思是用sed做一些regex替换,它必须匹配包含换行符的字符串。这离操作问题足够远,可以区分。
- 另一方面,--delete不适用于freebsd。只使用-d将使答案更易于移植。
- @Sopalajodearierez:OS X上相同
- @Sopalajodearierez是一个很好的观点。谢谢。
- 杰出的。尝试在textmate中的一个非常大的文件上执行此操作,但它会爆炸块。在几秒钟内完成。
- 有没有办法只移除
?
- @Aaronfranke不与tr合作。它适用于单个字符。
- GNU SED可以使用-i或--in-place命令行选项修改"就地"文件(通过使用临时文件),但tr不能。
将此解决方案与GNU sed一起使用:
1 2
| sed ':a;N;$!ba;s/
/ /g' file |
这将在一个循环中读取整个文件,然后用空格替换换行符。
说明:
通过:a创建标签。
通过N将当前行和下一行附加到模式空间。
如果我们在最后一行之前,那么分支到创建的标签$!ba($!)意味着不要在最后一行执行,因为应该有最后一行。
最后,替换用模式空间(即整个文件)上的一个空间替换每个换行符。
以下是与BSD和OS X的sed兼容的跨平台语法(根据@benjie comment):
1 2
| sed -e ':a' -e 'N' -e '$!ba' -e 's/
/ /g' file |
。
如您所见,使用sed解决这个简单的问题是有问题的。有关更简单和充分的解决方案,请参阅此答案。
- +解释和解决原始问题。
- 虽然tr工具可能是最好的方法,但我必须接受您的问题,因为它解决了问题。
- @Masi,所以你在Mac上得到不同的输出?MacOSX肯定知道sed命令;如果输出不同,我会有点失望。
- @Arjan和Masi:OSX使用的是BSD的sed,而不是GNU sed,因此两者之间可能存在一些细微的(和一些不那么细微的)差异。如果您同时在OSX和*NIX机器上工作,这是一种持续的痛苦。我通常在OSX上安装GNU的coreutils和findutils,忽略BSD版本。
- 阿扬:它不适用于Mac。它根本不会更改文件。
- :a不是寄存器,它是一个分支标签。它是b命令*的目标,其工作方式类似于"goto"。将其称为寄存器意味着您可以创建存储位置。只有两个"寄存器";一个称为"保留空间",脚本不使用该空间,另一个称为"模式空间"。N命令将输入文件的新行和下一行附加到模式空间。[*您可以有多个labels&b命令。如果您有一个没有附加标签字符的b命令,它将分支到脚本的末尾,以读取下一行并再次循环。]
- 这应该放在sed1line.txt中,当您希望在整个文件中读取模式空间时,它将对情况有所帮助。zseni&225;lis!
- 您可以通过单独执行命令而不是使用分号来运行这个跨平台(即在Mac OS X上):sed -e ':a' -e 'N' -e '$!ba' -e 's/
/ /g'。
- 这也适用于sed ':a;N;$!ba;y/
/ /'。
- 这也是sed ':a;{N;s/
/ /};ba':p
- 我也不明白,但是我的同步书签中有这个页面,所以我可以随时访问它。你会认为我会记得使用dmckee的解决方案(tr'''),这应该更容易(使用和记住)。
- 为什么没有人评论这是一个多么愚蠢的混乱(不是答案本身,而是提出答案的程序是一个非常简单的问题的最佳解决方案)。SED看起来像一辆通常运行良好的车,但是如果你想开车到附近的特定街道,唯一的方法就是用直升机把车抬起来。
- 输入的最后一行将不会被替换。例如,printf '1
2
3
' | sed ':a;N;$!ba;s/
/ /g'将给予1 2 3
。
- 拜托,伙计们-261票赞成一个疯狂的,不可理解的解决方案,但不起作用?????SED是一个很好的工具,可以在一条线上进行简单的替换,其他任何地方都可以使用awk。好悲伤……
- @埃德莫顿,你能不能请埃拉博罗谈谈什么不管用?
- @zsoltbotykai请参阅我前面的注释,并且的使用仅在某些操作系统上的某些SED中有效-在SED中指定换行的可移植方法是反斜杠,后跟一个文字换行符。只需阅读上面的评论——大约三分之一的人说这对他们不起作用,另外三分之一的人说他们不理解。你不应该把SED用于这种事情。
- @埃德莫顿,你说得对,我自己不使用它(tr就简单多了)。不过,问题是如何用我以前读过、理解并回答过的《以东记》(1)来做。对我来说,它是有效的(我确实理解它,尽管我已经阅读了一些文档来学习这个奇妙的工具)。
- 为什么":a;n;$!ba;s///g"工作而不仅仅是"s///g"?
- @trusktr请参阅此答案:stackoverflow.com/a/7697604/11621有一个从官方SED常见问题解答中复制的解释。
- 这也可以很好地替代xargs -0,特别是当您遇到"参数行太长"的错误时。
- 不适用于彩色输出。我在这个问答中尝试了所有方法,但当输出为ANSI彩色时,没有任何效果。在Ubuntu 13.04上测试
- 这是一个很好的资源,可以在使用sed时挤压新行字符。如果不想翻译整个文件,也可以使用此代码段来翻译一系列行。
- 行范围的翻译是什么?@Jonathan Neufeld错过了SED的答案:stackoverflow.com/questions/25947391/&hellip;
- 很好的例子。仅适用于其他-如果您有带insert-into的SQL文件…在一行使用insert into命令,在第二行使用values命令,而不是将它们与sed ':a;N;$!ba;s/
values/ values/g'合并为一行。
- 我想在一个文件中替换一些但不是所有的新行。例如,所有以上拉结束的线条。这是有效的:sed ':a;N;$!ba;s/PULLUP
/ /g;'。在这种情况下,使用SED很有用。
- 谢谢你的解释-教我们怎么钓鱼,而不仅仅是给我们鱼!
- 如果$!是"最后一行不做",那么为什么sed ':a;N;ba;s/
/ /g'(没有$!不起作用?
- @阿蒂的美元!使整个封装将所有行累积到模式缓冲区中,然后从该缓冲区进行大量替换并一次性打印。
- 为GNU和BSD工作,谢谢!!
- 用链接替换文件,但仍在此处。
- 对于BSD SED解决方案,这里唯一的要求是在标签后拆分命令。因此,sed -e ':a' -e 'N;$!ba' -e 's/
/ /g'就足够了。
- 如何建造和使用空间站从轨道上击打头部的钉子,这是一个完美的描述,但也许应该使用锤子,也就是tr命令。
- 这在某些SED的一行输入中失败:尝试printf 'abc
' | sed ':a;N;$!ba;s/
/ /g'。解决这个问题的方法(也是一个通用的解决方案)是使用:printf 'abc
' | sed ':a;$!{N;ba};s/
/ /g'。
快速回答:
1 2
| sed ':a;N;$!ba;s/
/ /g' file |
:a创建标签"a"
n将下一行附加到模式空间
$!如果不是最后一行,则BA分支(转到)标签为"A"
s substitute,//regex替换新行,//用空格,/g全局匹配(尽可能多次)
sed将循环执行步骤1到3,直到到达最后一行,使所有行都适合模式空间,其中sed将替换所有字符
选择:
与SED不同的是,所有备选方案都无需到达最后一行即可开始该过程。
用重击,慢
1
| while read line; do printf"%s""$line"; done < file |
号
使用Perl、Sed-like速度
1 2
| perl -p -e 's/
/ /' file |
用tr,比sed快,只能替换一个字符
。
使用粘贴,类似于tr的速度,只能替换为一个字符
带awk,tr-like速度
。
"echo$(SED常见问题5.10的长答案:
5.10。为什么不能使用转义符匹配或删除换行符?顺序?为什么不能使用匹配2行或更多行?
将永远不匹配行尾的换行符,因为在将换行符放入图案空间。要将两条或多条线放入图案空间,请使用'n'命令或类似的命令(例如'h;…;g;')。
塞德的作品是这样的:塞德一次读一行,删掉终止换行符,将剩余内容放入模式空间,SED脚本可以寻址或更改它,并且当模式空间是打印的,在stdout(或文件)上附加新行。如果模式空间全部或部分用"d"或"d"删除,在这种情况下不添加换行符。因此,脚本
1 2 3 4 5
| sed 's/
//' file # to delete newlines from each line
sed 's/
/foo
/' file # to add a word to the end of each line |
。
不会起作用,因为后面的换行符在线条被放入图案空间。要执行上述任务,使用以下脚本之一:
1 2 3 4 5
| tr -d '
' < file # use tr to delete newlines
sed ':a;N;$!ba;s/
//g' file # GNU sed to delete newlines
sed 's/$/ foo/' file # add"foo" to end of each line |
因为除了GNU以外的其他版本的SED的大小限制为模式缓冲区,unix的"tr"实用程序在这里是首选的。如果文件的最后一行包含换行符,GNU SED将添加该换行到输出,但删除所有其他内容,而tr将删除所有换行。
要匹配由两行或多行组成的块,有三个基本选项:(1)使用"n"命令将下一行添加到图案空间;(2)使用"h"命令至少两次以附加当前行到保留空间,然后从保留空间检索行对于X、G或G;或(3)使用地址范围(见上文第3.3节)匹配两个指定地址之间的行。
选项(1)和(2)将在模式空间中放置一个可以根据需要编址("s/abcxyz/alphabet/g")。一个例子第4.13节中出现了使用"n"删除一个行块的方法。(如何删除特定连续行块?)这个示例可以通过将delete命令更改为否则,如"P"(打印)、"I"(插入)、"C"(更改)、"A"(附加),或"S"(替代)。
选项(3)不会将放入模式空间,但会匹配一个连续的行块,因此可能不匹配甚至需要来查找您要查找的内容。自GNU SED以来版本3.02.80现在支持此语法:
1
| sed '/start/,+4d' # to delete"start" plus the next 4 lines, |
。
除了传统的"/from here/,/to there/…"范围之外地址,可能会完全避免使用。
- 不适用于彩色输出。我在这个问答中尝试了所有方法,但当输出为ANSI彩色时,没有任何效果。在Ubuntu 13.04上测试
- @elgalu试试这个unix.stackexchange.com/questions/4527/&hellip;
- 关于这个答案,最好的部分是"长答案"准确地解释了命令的工作方式和原因。
- 这可能是我在StackExchange上看到的成千上万个答案中最有用的一个。我需要跨行匹配多个字符。以前的SED示例中没有涉及多行,而tr无法处理多字符匹配。Perl看起来不错,但并不像我期望的那样工作。如果可以的话,我会把这个答案投几次票。
- 我需要用多个字符替换,我真的很喜欢这个答案的深度和组织性。我的命令样本是:awk 1 ORS='\\
'。从Thor的回答中读取1的含义,awk程序的真实情况只需打印每一行输入即可。
- 感谢您使用"粘贴"命令。我不知道那个。我有一个带有一些URL的文件,我想在Chrome浏览器中同时打开它们。所以我(在Mac OS X上):paste -s -d ' ' url.txt | xargs open工作得很好。
- @XL-T您应该使用xargs -a url.txt open。
- 回答得好。在bash选项中有一个小问题。它将在被解释为回声开关的线路上失效。这就是为什么我从不使用echo来打印变量数据的原因。用printf '%s'"$line"代替。
- tr是一个很好的主意,你的全面报道提供了一个高质量的答案。
- +1用于(标准实用程序)paste…还有其他人!
较短的awk替代方案:
解释
awk程序由条件代码块组成的规则组成,即:
1
| condition { code-block } |
号
如果省略代码块,则使用默认值:{ print $0 }。因此,1被解释为一个真实条件,每条线路执行print $0。
当awk读取输入时,它根据RS的值(记录分隔符)将输入拆分成记录,默认值为换行,因此awk默认情况下将按输入行进行解析。拆分还涉及从输入记录中剥离RS。
现在,在打印记录时,ORS(输出记录分隔符)会附加到该记录上,默认值又是一个换行符。因此,通过将ORS改为空间,所有新行都改为空间。
- 清晰、简单、优雅、实用!+ 1。
- 我非常喜欢这个简单的解决方案,它比其他解决方案更易于阅读。
- 如果更合理的话,这可以有效地写为:awk 'BEGIN { ORS="" } { print $0 } END { print"
"} ' file.txt(添加一个结束换行来说明开始/结束);"1"评估为true(处理行)和print(打印行)。条件也可以添加到此表达式中,例如,只处理与模式匹配的行:awk 'BEGIN { ORS="" } /pattern/ { print $0 } END { print"
"} '。
- 我喜欢这种方法,应该给予更多的赞成票。
- 你可以做得更简单:codeawk'ors=''file.txt code。
- 当使用这样的awk时,不幸的是,文件中的最后一行提要也会被删除。请参阅上面关于在类似"cat file"echo$(tr" 12""")的子shell中使用"tr"的patrick dark答案,它起到了关键作用。Nifty。
GNU SED有一个用于空分隔记录(行)的选项-z。你可以打电话给:
- 即使输入不包含空值,它们也将被保留(作为记录分隔符)。
- 如果没有空值,这不会加载整个输入吗?在这种情况下,处理一个千兆字节的文件可能会崩溃。
- @Ruslan,是的,它加载整个输入。此解决方案不适用于多GB文件。
- 这真的是最好的答案。其他的表达方式被扭曲得记不起来了。@jjoao你可以和-u, --unbuffered一起使用。man映像表示:"从输入文件加载最少数量的数据,并更频繁地刷新输出缓冲区"。
- 所以。很多。这个。
Perl版本的工作方式与您期望的一样。
1 2
| perl -i -p -e 's/
//' file |
。
正如评论中指出的,值得注意的是,这些编辑已经到位。在替换之前,-i.bak将为您提供原始文件的备份,以防您的正则表达式不如您想象的那么智能。
- 请至少提到没有后缀的-i不做备份。-i.bak保护您免受一个简单、丑陋的错误(例如,忘记键入-p并将文件归零)。
- @泰勒马科斯:这是一个公平的观点,但可以用任何一种方式来辩论。我没有提到的主要原因是OP问题中的SED示例没有进行备份,因此在这里似乎是多余的。另一个原因是我从来没有实际使用过备份功能(实际上,我觉得自动备份很烦人),所以我总是忘记它的存在。第三个原因是它使我的命令行长了四个字符。无论好坏(可能更糟),我是一个强迫性的极简主义者;我只是喜欢简洁。我知道你不同意。我将尽我最大的努力记住在将来警告备份。
- @愤怒和诅咒:事实上,你刚刚为忽视我提出了一个该死的好理由。也就是说,你的选择是有理由的,不管我是否同意这些选择,我当然尊重。我不完全确定原因,但最近我对这个特别的事情感到非常失望(Perl中的-i标志没有后缀)。我相信我很快就会找到别的事情来困扰我。:)
- 不知怎的,Perl在Linux中工作,而Sed没有?!
- 不幸的是,通过为文件名指定-,这不适用于stdin。有办法吗?这就是我不必担心修改文件的方法,即使用以cat开头的管道。
- @如果没有提供文件名,Stevenlu Perl将默认从stdin中读取。所以你可以这样做,比如perl -i -p -e 's/
//' < infile > outfile。
谁需要sed?这是bash路:
1
| cat test.txt | while read line; do echo -n"$line"; done |
号
- upvote,我通常使用最上面的答案,但是当管道/dev/urandom通过它时,sed在eof之前不会打印,并且^c不是eof。此解决方案每次看到换行符时都会打印。正是我需要的!谢谢!
- 那么为什么不呢:echo-n`cat days.txt`来自这篇文章
- @Tony,因为backticks被弃用,cat是多余的;-)使用:echo$(
- 甚至不使用cat:while read line; do echo -n"$line"; done < test.txt。如果子shell有问题,可能会很有用。
- echo $(将所有空白压缩到一个单独的空间,而不仅仅是换行:这超出了OP的要求。
- 除了要求的内容外,还将删除所有前导/训练空白字符和反斜杠字符。不要只使用shell循环来操作文本,它始终是错误的方法。
- @艾德…$(与bash&ksh合作。它不适用于更基本的"posix"shell实现(dash、ash、原始的bourneshell变体)。对于我尝试过的后一种实现,构造不会产生输出(也不会产生错误)。有趣的是,它仍然适用于bash --posix。我没有足够的信息来确定这是否是一个错误。posix shell页面根本没有提到$(。
- @胡安·伊德克,但我想你可能想跟格伦谈谈,我从来没有提到过埃多克斯。我想有一次卡洛和格伦斯之间,格伦斯和我的之间,还有一些其他的评论被删除了,所以我们的评论的上下文丢失了。
- 预计起飞时间。。。对不起的。你说得对,我是说@glenn jackman。当当,错过了评论的编辑窗口。
- 冒昧地说,我不希望$(抛出错误。这是一个有效的重定向,但是没有命令来处理输入。在dash中,本身不会产生输出,也不会产生错误,在$()创建的子shell中也会得到相同的结果。
- 你也可以通过使用printf来避免对echo -n的抨击。
- 如果不设置ifs,我想这也会删除制表符和连续空格?
为了使用awk将所有换行符替换为空格,而不将整个文件读取到内存中:
1
| awk '{printf"%s", $0}' inputfile |
如果您想要最后一行:
1 2
| awk '{printf"%s", $0} END {printf"
"}' inputfile |
。
可以使用空格以外的字符:
1 2
| awk '{printf"%s|", $0} END {printf"
"}' inputfile |
。
号
是命令。
简单易用。
- 如果你不想增加一个空格,也可以简单地用EDOCX1[6]
三件事。
绝对不需要tr(或cat等)。(gnu)sed和(gnu)awk组合在一起时,可以完成99.9%的任何文本处理。
流!=基于行。ed是一个基于行的编辑器。sed不是。有关差异的更多信息,请参阅SED讲座。大多数人将sed混淆为基于行,因为默认情况下,EDOCX1对简单匹配的模式匹配不是很贪婪——例如,当执行模式搜索并替换为一个或两个字符时,默认情况下,它只替换找到的第一个匹配(除非全局命令另有规定)。如果它是基于行而不是基于流的,那么甚至没有全局命令,因为它一次只计算行。试着运行ed;你会注意到区别。如果您想在特定的行上迭代(例如在for循环中),ed非常有用,但是大多数时候您只需要sed。
据说,
1 2
| sed -e '{:q;N;s/
/ /g;t q}' file |
号
在GNU sed版本4.2.1中工作正常。上面的命令将用空格替换所有换行符。打字很难看,也有点笨重,但效果很好。{}可以忽略不计,因为它们只是出于理智的原因才包括在内。
- 什么是one?我不知道这个命令!
- 作为一个只知道足够多的sed来做基本的事情的人,我不得不说,这不仅仅是关于你可以用sed做什么,而是关于理解发生了什么是多么容易。我和sed一起工作非常困难,所以当我可以使用它时,我更喜欢使用更简单的命令。
- 使用t q作为条件跳转,这可以使用类似s/
/ /的模式(连接以空格开头的所有行),而无需将整个文件读取到内存中。转换多兆字节文件时很方便。
- 你链接的文章没有反映你所说的内容
- 这比大输入时接受的答案慢了近800倍。这是因为在越来越大的输入上运行每一行的替换。
答案是:一个标签…
如何使用sed替换换行符()?
…在命令行的freebsd 7.2中不工作:
1 2 3 4 5 6 7
| ( echo foo ; echo bar ) | sed ':a;N;$!ba;s/
/ /g'
sed: 1:":a;N;$!ba;s/
/ /g": unused label 'a;N;$!ba;s/
/ /g'
foo
bar |
但是,如果您将SED脚本放在一个文件中,或者使用-e"构建"SED脚本…
1 2 3
| > (echo foo; echo bar) | sed -e :a -e N -e '$!ba' -e 's/
/ /g'
foo bar |
。
或者…
1 2 3 4 5 6 7 8 9 10
| > cat > x.sed << eof
:a
N
$!ba
s/
/ /g
eof
> (echo foo; echo bar) | sed -f x.sed
foo bar |
也许OSX中的SED是类似的。
- 这一系列的-e参数在使用mks的Windows上对我很有用!谢谢!
您可以使用xargs:
。
或
- 这对file没有任何影响…
- 为我工作:xargs < file.txt。
易于理解的解决方案
我有这个问题。更重要的是,我需要解决方案来处理BSD(Mac OS X)和GNU(Linux和Cygwin)的sed和tr:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $ echo 'foo
bar
baz
foo2
bar2
baz2' \
| tr '
' '\000' \
| sed 's:\x00\x00.*:
:g' \
| tr '\000' '
' |
号
输出:
(有尾随换行符)
它可以在Linux、OS X和BSD上工作——即使没有UTF-8支持或使用蹩脚的终端。
使用tr将换行符与另一个字符交换。
NULL(\000或\x00很好,因为它不需要utf-8支持,而且不太可能被使用。
使用sed匹配NULL。
如果需要,可以使用tr交换额外的换行符。
- 关于术语的一个微妙的注释:\000字符通常被称为NUL(1 L),而EDCOX1×5Ω通常在讨论零指针(C/C++)时使用。
我不是专家,但我猜在sed中,您首先需要将下一行附加到模式空间中,bij使用"N"。从SED&awk(Dale Dougherty和Arnold Robbins;O'Reilly 1997;预览版第107页)的"高级SED命令"中的"多行模式空间"部分:
The multiline Next (N) command creates a multiline pattern space by reading a new line of input and appending it to the contents of the pattern space. The original contents of pattern space and the new input line are separated by a newline. The embedded newline character can be matched in patterns by the escape sequence"
". In a multiline pattern space, the metacharacter"^" matches the very first character of the pattern space, and not the character(s) following any embedded newline(s). Similarly,"$" matches only the final newline in the pattern space, and not any embedded newline(s). After the Next command is executed, control is then passed to subsequent commands in the script.
号
来自man sed:
[2addr]N
Append the next line of input to the pattern space, using an embedded newline character to separate the appended material from the original contents. Note that the current line number changes.
号
我用它来搜索(多个)格式不正确的日志文件,在这些文件中,搜索字符串可能在"孤立"的下一行中找到。
为了响应上述"tr"解决方案,在Windows上(可能使用tr的gnuwin32版本),建议的解决方案:
号
不适用于我,它可能出错,或者由于某种原因实际替换了 w/""。
使用tr的另一个特性,"删除"选项-d确实起作用,但是:
号
或"r"而不是"n"
- 在Windows上,您可能需要使用tr"
""" < input。Windows Shell(cmd.exe)不将撇号视为引用字符。
- 不,在Windows10 Ubuntu子系统中,您需要使用tr"
""" < input.txt > output.txt
。
- 这在使用gnuwin32:cat SourceFile.txt | tr --delete '
' > OutputFile.txt
的Windows10上工作。或者,使用gow(Windows上的gnu),而不是gnuwin32,github.com/bmatzelle/gow/wiki
我使用了一种混合方法来绕过换行问题,使用tr将换行替换为制表符,然后用我想要的任何内容替换制表符。在本例中,""因为我正在尝试生成HTML分隔符。
1 2 3 4 5
| echo -e"a
b
c
" |tr '
' '\t' | sed 's/\t/ /g'` |
。
在某些情况下,您可以将RS更改为其他字符串或字符。这样,SUB/GSUB可以使用:
1 2
| $ gawk 'BEGIN {RS="dn" } {gsub("
","") ;print $0 }' file |
shell脚本的强大之处在于,如果您不知道如何以某种方式执行,那么可以以另一种方式执行。很多时候,你要考虑的事情比在一个简单的问题上做一个复杂的解决方案还要多。
关于呆呆的事情…把文件读到内存中,我不知道这一点,但对我来说,gawk似乎一次只处理一行,而且速度非常快(不像其他的一些那样快,但是写和测试的时间也很重要)。
我处理MB甚至GB的数据,我发现的唯一限制是行大小。
防弹解决方案。二进制数据安全且符合POSIX,但速度慢。
位置SED需要根据POSIX文本文件和十字槽线定义,因此不允许使用空字节和过长的行,并且每行必须以换行符结尾(包括最后一行)。这使得使用SED处理任意输入数据变得困难。
下面的解决方案避免了SED,而是将输入字节转换为八进制代码,然后再次转换为字节,但会截取八进制代码012(换行符),并输出替换字符串来代替它。据我所知,该解决方案是符合POSIX的,因此它应该在各种平台上工作。
1 2 3 4 5
| od -A n -t o1 -v | tr ' \t' '
' | grep . |
while read x; do ["0$x" -eq 012 ] && printf '
' || printf"\\$x"; done |
POSIX参考文档:嘘,shell命令语言,OD,TR,格雷普读,[打印。
read、[和printf都是至少在bash中内置的,但这可能不是由posix保证的,因此在某些平台上,每个输入字节可能会启动一个或多个新进程,这将减慢速度。即使在bash中,这个解决方案也只能达到50kb/s左右,因此它不适用于大型文件。
在Ubuntu(bash、dash和busybox)、freebsd和openbsd上测试。
您可以使用xargs&mdash;默认情况下,它将用空格替换
。
但是,如果您的输入有任何unterminated quote的情况,例如给定行上的引号不匹配,则会出现问题。
我特别喜欢的解决方案是将所有文件追加到保留空间,并替换文件末尾的所有换行符:
1 2 3
| $ (echo foo; echo bar) | sed -n 'H;${x;s/
//g;p;}'
foobar |
然而,有人说在某些SED实现中保留空间是有限的。
- 在您的答案中用空字符串替换的内容隐藏了这样一个事实:总是使用h来附加到保留空间,这意味着保留空间将以换行符开始。为了避免这种情况,您需要使用1h;2,$H;${x;s/
/x/g;p}。
在Mac OS X上(使用freebsd-sed):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # replace each newline with a space
printf"a
b
c
d
e
f" | sed -E -e :a -e '$!N; s/
/ /g; ta'
printf"a
b
c
d
e
f" | sed -E -e :a -e '$!N; s/
/ /g' -e ta |
号
使用awk:
1
| awk"BEGIN { o="" } { o=o " " \$0 } END { print o; }" |
号
- 如果您将外部引号更改为单引号,则无需跳过引号和美元符号。字母"O"通常被认为是一个错误的变量名,因为它可能与数字"0"混淆。您也不需要初始化变量,它默认为空字符串。但是,如果你不想要一个外部的领导空间:awk '{s = s sp $0; sp =""} END {print s}'。但是,请参阅我的答案,了解使用awk而不将整个文件读取到内存中的方法。
- 请查看托尔的答案。它比这种方法更有效、更易读,而且通过各种方式都更好(即使这样也行)!
- 伙计,我明白了。没必要在我脸上擦一下:()托尔的答案就在上面的那一页上(没错),你在乎什么?
用任何字符串替换换行符,也替换最后一个换行符
纯tr解只能替换为单个字符,纯sed解不能替换输入的最后一行。以下解决方案解决了这些问题,并且似乎对二进制数据(即使使用UTF-8区域设置)是安全的:
1 2 3 4 5 6
| printf '1
2
3
' |
sed 's/%/%p/g;s/@/%a/g' | tr '
' @ | sed 's/@//g;s/%a/@/g;s/%p/%/g' |
号
结果:
号
- 这很糟糕,因为它会在任何包含@的输入上产生不需要的输出。
- @史蒂文鲁:不,输入中的@正常。它逃到了以东十一号[二号],然后又回来了。不过,该解决方案可能不完全符合POSIX(不允许使用空字节,因此对二进制数据不好,而且所有行都必须以换行符结尾,因此tr输出不是真正有效的)。
- 啊。我看你已经修好了。有点费解什么应该是一个简单的操作,但良好的工作。
在"正常"替换后引入新行的是SED。首先,它修剪新行字符,然后根据您的指示进行处理,然后引入新行。
使用sed,您可以在每一输入行被修剪后用您选择的字符串替换行的"结束"(而不是新行字符);但是,sed将输出不同的行。例如,假设您想将"行尾"替换为"=="(比替换为单个空格更通用):
1 2 3 4 5 6 7 8 9 10
| PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF
first line===
second line===
3rd line===
PROMPT~$ |
要用字符串替换新行字符,您可以使用tr(如前所述)将新行字符替换为"特殊字符",然后使用sed将该特殊字符替换为所需的字符串。
例如:
1 2 3 4 5 6 7 8
| PROMPT~$ cat <<EOF | tr '
' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF
first line===second line===3rd line===PROMPT~$ |
号
删除空行:
号
- 这是给GNU SED的。在正常的SED中,这给了sed: 1:"s/^$//;t;p;": undefined label ';p;'。
另一个gnu sed方法,几乎与zsolt botykai的答案相同,但它使用了sed较不常用的y命令(transliterate),这节省了一个字节的代码(后面的G:
号
人们希望y的运行速度比s快(可能是tr的速度快20倍),但在GNU SED v4.2.2中,y比s慢4%。
更便携的BSD sed版本:
1 2
| sed -e ':a' -e 'N;$!ba' -e 'y/
/ /' |
号
- 对于BSD SED y,大约快15%。请参阅此答案了解一个工作示例。
- 此外,由于BSD SED命令需要在标签后终止,因此sed -e ':a' -e 'N;$!ba' -e 'y/
/ /'将是解决问题的方法。
你也可以用这个方法
1 2
| sed 'x;G;1!h;s/
/ /g;$!d' |
。
解释
1 2 3 4 5 6 7 8
| 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
is
available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
last line. |
。
Flow:当第一行从输入中获取时,进行交换,因此1转到保留空间,然后转到模式空间,然后将保留空间追加到模式空间,然后执行替换并删除模式空间。在进行第二行交换时,2到保持空间,1到图案空间,然后G将保持空间追加到图案空间,然后h将图案复制到图案空间,进行替换并删除。此操作将继续,直到达到EOF,然后打印准确的结果。
- 但是,要注意,echo 'Y' | sed 'x;G;1!h;s/
/X/g;$!d'导致XY。
如果您不幸不得不处理Windows行尾,则需要删除
和
。
1 2 3
| tr '[
]' ' ' < $input > $output |
@op,如果要替换文件中的换行符,只需使用dos2unix(或unix2dox)
1
| dos2unix yourfile yourfile |
。
- 你能在你的答案中添加更多的信息吗(链接是否足够)?例如,dos2unix在哪里?它是独立程序吗?它是大包装的一部分吗?它在什么平台上运行(只有Unix?只有Windows?)
- 这只会消除
--而不是。我一直在为此使用SED…sed-i-e's/
$/'foo比这些工具对我来说更强大。
1 2 3
| sed '1h;1!H;$!d
x;s/
/ /g' YourFile |
号
这不适用于大型文件(缓冲区限制),但如果有足够的内存来保存文件,则效率非常高。(修正H->1h;1!H,经过@hilojack的好评)
另一个版本在读取时更改新行(更多CPU,更少内存)
1 2 3 4 5
| sed ':loop
$! N
s/
/ /
t loop' YourFile |
号
- 它不像示例sed ':a;N;$!ba;s/
/ /g'那样有效。另一方面,输出具有额外的空格字符。
- 对,纠正了
- 循环版本类似于这个答案,正如我在这里的评论中指出的,它慢了大约800倍。
使用allowing查找和替换
1 2 3 4
| sed -ie -z 's/Marker
/# Marker Comment
Marker
/g' myfile.txt |
号
Marker
号
变成
# Marker Comment
Marker
号
我发布这个答案是因为我尝试过上面提供的大多数sed推荐示例,这些示例在我的Unix系统中不起作用,并且给了我错误消息Label too long: {:q;N;s/
/ /g;t q}。最后,我提出了我的要求,并在此共享了适用于所有UNIX/Linux环境的内容:
1 2
| line=$(while read line; do echo -n"$line"; done < yoursourcefile.txt)
echo $line |sed 's/ //g' > sortedoutput.txt |
号
第一行将删除文件yoursourcefile.txt中的所有新行,并生成一行。第二个sed命令将删除其中的所有空间。
这可能适用于您(GNU SED):
1
| sed 'H;$!d;x;:a;s/^((.).*)\2/\1 /;ta;s/.//' file |
H命令在模式空间前加新行,然后将结果附加到保留空间。SED的正常流程是从每行中删除以下换行符,因此这将在保留空间的开头引入换行符,并复制文件的其余部分。一旦文件被拖进保留空间,将保留空间与模式空间交换,然后使用模式匹配将所有原始换行替换为空格。最后,删除引入的换行符。
这样做的好处是,在sed命令中永远不会实际输入换行字符串。
还可以使用标准文本编辑器:
1 2 3 4
| printf '%s
%s
%s
' '%s/$/ /' '%j' 'w' | ed -s file |
号
注意:这会将结果保存回file。
与sed一样,此解决方案也会遇到先将整个文件加载到内存中的问题。
这真的很简单…当我找到解决方案时,我真的很生气。只少了一个反斜杠。就是这样:
1 2
| sed -i"s/\\\\
//g" filename |
我认为最简单和最快的方法是使用grep。在regexp egrep或aka grep -E中使用grep有一个捷径,所以我们要做的只是
1
| egrep '^\S.+' fileNameWithUnneededNewLines > ClearedFile |
。
- 不,这将找到以非空白字符(\S)开头,后跟任何字符的行。新行分隔
这里是没有缓冲区的sed(对于实时输出很好)。示例:用HTML中的
break替换
。
1 2 3
| echo -e"1
2
3" | sed 's/.*$/&<br\/>/' |
号
以下内容比大多数答案简单得多。同时,它也起作用:
1
| echo `sed -e 's/$/\ |\ /g' file` |
- 这不起作用,因为它不替换换行符,而是在每行前面加上一些文本。
1 2 3 4 5
| sed -i ':a;N;$!ba;s/
/,/g' test.txt
tr"
" <file name> |
试试这个:
1 2 3
| echo"a,b"|sed 's/,/
/' |
号
在SED替换部件中,键入反斜杠,按Enter键转到第二行,然后以/g'结束:
1 2 3 4 5 6 7 8 9 10
| sed 's/>/\
/g'
[root@localhost ~]# echo"1st</first>2nd</second>3rd</third>" | sed 's/>/\
> /g'
1st</first
2nd</second
3rd</third
[root@localhost ~]# |
。
- 这不是我们要求的。
- 棒棒糖根壳或胸围
- 但是需要注意的一点是,对于可移植性,有时需要在脚本中使用新行(而不是)。有了一些技巧,您还可以插入文字
。我的意思是在脚本文件中插入真正的字符,而不是转义。