我正在使用sed来修改文本文件的第一部分。问题是 sed 会自动在文件末尾引入一个空行。
你知道怎么解决吗?(不使用截断,因为我不想在MacOS中安装其他软件)
谢谢!!
对您的问题的快速回答是将您的输出传输到另一个 cmd,例如awk
:
sed 'commands' file | awk '(NR>1){printf "%sn",l}{l=$0}END{printf "%s",l}'
这将删除最后一个<newline>
。这不能通过sed
来完成,下面的答案试图解释它。更多可能性可以在如何删除换行符中找到,如果换行符是文件中的最后一个字符?
为什么sed
总是以<newline>
结束?这个问题的答案取决于对标准的解释和您使用sed
的实施。
根据sed
标准:
在默认操作中,
sed
循环地附加一行输入, 减去其终止<newline>
字符,进入模式空间。如果模式中有<newline>
,则应跳过从输入读取 结束上一个循环的D
命令之前的空格。sed 实用程序 然后,应按顺序应用其地址选择的所有命令 模式空间,直到命令开始下一个循环或退出。如果没有 命令显式启动一个新循环,然后在脚本结束时 模式空间应复制到标准输出(除非-n
)并删除图案空间。每当 模式空间写入标准输出或命名文件,sed
立即用<newline>
紧随其后.
这意味着两件事:
- 如果行未由
<newline>
终止,则不会处理该行。 - 任何写入标准输出的内容都以
<newline>
终止,即由于命令周期结束或p
或P
发出命令而导致的输出。
示例:sed (SunOS 5.10) SUNWcsu 11.10.0 rev=2005.01.21.15.53
$ echo -n foo | sed 'p'
$ echo -n 'foonbar' | sed 'p'
foo
foo
显然,如果没有被<newline>
终止的行,则没有处理。否则,<newlines>
将添加到任何输出中。
MacOSsed
手册具有与posix类似的插入。
通常,
sed
循环复制一行输入,不包括其 终止换行符,进入 模式空间(除非在D
函数之后还有剩余的东西)应用所有命令 对于选择该模式空间的地址,将模式空间复制到标准输出,追加追加 换行符,然后删除模式空间。
这没有经过测试,因为我没有 mac。
GNUsed
手册似乎对这个问题的看法略有不同:
sed
通过在每行输入上执行以下循环来操作: 首先,SED 从输入流中读取一行,删除任何尾随 换行符,并将其放置在模式空间中。然后命令是 执行;每个命令都可以有一个与之关联的地址:地址 是一种条件代码,只有在 在执行命令之前验证条件。当到达脚本末尾时,除非正在使用
-n
选项,否则模式空间的内容将打印到输出流中,如果删除了尾随换行符,则会重新添加。
这意味着以下内容:
- 所有行都已处理,全部或不由
<newline>
终止 - 如果达到命令周期的末尾,则添加与最初删除的相同数量的
<newline>
。
例 :sed (GNU sed) 4.2.2
在以下示例中,仅在p
之后添加换行符,而不是在循环结束后添加换行符。(换行符在十六进制中012
)
$ echo -n foo | hexdump -b
0000000 146 157 157
0000003
$ echo -n foo | sed --posix 'p' | hexdump -b
0000000 146 157 157 012 146 157 157
0000007
脚注7对此进行了解释:
实际上,如果
sed
打印一行没有终止换行符,则 尽管如此,一旦有更多文本,就会打印缺少的换行符 发送到相同的输出流,这给出了"最不期望的" 惊喜",即使它不会发出类似sed -n p
的命令 与cat
完全相同。
结论:根据 posix 标准,您最终将始终得到一个以<newline>
结尾的输出文件,但它可能不是输入的最后一行。根据 Gnu 手册,您的输出终止与输入文件末尾的输出量相同。
问题:GNU 的sed --posix
是真正的 posix 吗?