sed 可以替换换行符吗?

Jim*_*Jim 67 sed

sed 和换行符有问题吗?
我有一个包含以下内容的文件 test.txt

aaaaa  
bbbbb  
ccccc  
ddddd  
Run Code Online (Sandbox Code Playgroud)

以下不起作用:
sed -r -i 's/\n/,/g' test.txt

我知道我可以使用tr它,但我的问题是为什么 sed 似乎不可能。

如果这是逐行处理文件的副作用,我会对为什么会发生这种情况感兴趣。我认为grep删除新行。sed 也一样吗?

Ant*_*hon 65

使用 GNUsed并提供POSIXLY_CORRECT不在环境中(用于单行输入):

sed -i ':a;N;$!ba;s/\n/,/g' test.txt
Run Code Online (Sandbox Code Playgroud)

来自/sf/ask/87639961/

  1. 通过创建标签 :a
  2. 通过将当前行和下一行附加到模式空间 N
  3. 如果我们在最后一行之前,则分支到创建的标签$!ba$!意味着不要在最后一行执行此操作(因为应该有一个最后的换行符))。
  4. 最后,替换用模式空间(即整个文件)上的逗号替换每个换行符。


Hie*_*nga 55

这适用于 GNU sed

sed -z 's/\n/,/g' 
Run Code Online (Sandbox Code Playgroud)

-z 自 4.2.2 起包含在内

注意。-z将分隔符更改为空字符 ( \0)。如果您的输入不包含任何空字符,则整个输入将被视为一行。这可能有其局限性

为避免替换最后一行的换行符,您可以将其改回:

sed -z 's/\n/,/g;s/,$/\n/'
Run Code Online (Sandbox Code Playgroud)

(这又是 GNUsed语法,但这并不重要,因为整个事情只是 GNU)

  • 这也将替换可能不是 OP 想要的尾随换行符......将结果与 _mikeserv_ 的解决方案进行比较。 (5认同)

mik*_*erv 11

sed总是\n在填充模式空间之前删除尾部的ewline,然后在写出其脚本的结果之前附加一个。\n可以通过各种方式在模式空间中使用ewline - 但如果它不是编辑的结果,则永远不会。这很重要 -的模式空间中的\newlinessed始终反映更改,并且永远不会出现在输入流中。\newlines 是sedder 可以依靠未知输入的唯一分隔符。

如果你想\n用逗号替换所有的ewlines 并且你的文件不是很大,那么你可以这样做:

sed 'H;1h;$!d;x;y/\n/,/'
Run Code Online (Sandbox Code Playgroud)

这会将每个输入行附加到h旧空间 - 除了第一个,它会覆盖h旧空间 - 跟随一个\newline 字符。然后它从输出中d删除每一行而不是$!最后一行。在最后一行Hold 和 pattern 空格被x更改,所有\newline 字符都被y///转换为逗号。

对于大文件,这种事情必然会导致问题 -sed线边界上的缓冲区,很容易被此类操作溢出。


小智 9

来自 Oracle 的网站:

sed 实用程序通过将文件一行一行地顺序读入内存来工作。然后,它执行为该行指定的所有操作,并将该行放回内存中以将所请求的更改转储到终端。在对这一行执行完所有操作后,它会读取文件的下一行并重复该过程,直到完成该文件。

基本上这意味着因为 sed 正在逐行读取换行符不匹配。

/sf/ask/87639961/的解决方案是:

sed ':a;N;$!ba;s/\n/,/g'
Run Code Online (Sandbox Code Playgroud)

或者,在便携式版本中(;在跳转标记标签后不连接)

sed -e ':a' -e 'N;$!ba' -e 's/\n/,/g'
Run Code Online (Sandbox Code Playgroud)

该页面上提供了有关其工作原理的说明。


小智 5

你的帖子实际上有两个问题:

sed 可以替换新行字符吗?

是的。绝对没错。任何 sed 都可以:

s/\n/,/g
Run Code Online (Sandbox Code Playgroud)

或者

y/\n/,/
Run Code Online (Sandbox Code Playgroud)

这会将任何换行符(进入模式空间)转换为逗号。

sed 和换行符有问题吗?

是的,sed 中的换行符有几个问题:

  • 默认情况下,sed 将在模式空间中放置一个有效的。某些 sed 对行的长度和接受 NUL 字节有限制。一行以换行符结束。因此,一旦在输入中找到换行符,输入就会被分割,然后 sed删除换行符并将剩下的内容放置在模式空间中。因此,大多数时候,没有换行符进入模式空间。
  • 只有通过编辑模式空间才能添加/插入/编辑换行符。
  • sed 的每个连续输出几乎总是会附加一个换行符。
  • 如果输入的最后一行缺少换行符,GNU sed 能够避免打印尾随换行符。
  • 只有 GNU sed 能够使用另一个分隔符代替换行符(即带有 -z 选项的 NUL 字节)。

所有上述几点使得将换行符“转换”为任何内容都变得困难。
而且,如果换行符被另一个文本字符替换,那么 sed必须在内存中包含整个文本文件(无论使用什么进程到达那里)。

在 sed 中捕获内存中整个文件的几个解决方案是:

sed 'H;1h;$!d;x;y/\n/,/'   file      # most seds. [1]
sed ':a;N;$!ba;s/\n/,/g'   file      # GNU sed.   
sed -z 's/\n/,/g;s/,$/\n/' file      # GNU sed.
Run Code Online (Sandbox Code Playgroud)

一些不占用太多内存的快速解决方案是:

tr '\n' ',' file ; echo
awk '{printf("%s%s",NR==1?"":",",$0)}END{print ""}' file
Run Code Online (Sandbox Code Playgroud)

1来自 sed 解决方案:对于每一行,H 将行添加到保留空间(除了第一行完全替换保留空间(避免前导换行符)),然后擦除模式空间$!d(除了最后一行) 。在未被删除的最后一行上,其余命令将被执行。首先,获取保留空间中捕获的所有行x,然后用逗号替换所有换行符y/\n/,/