root@u1804:~# sed --version
sed (GNU sed) 4.5
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jay Fenlason, Tom Lord, Ken Pizzini,
and Paolo Bonzini.
GNU sed home page: <https://www.gnu.org/software/sed/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-sed@gnu.org>.
root@u1804:~#
Run Code Online (Sandbox Code Playgroud)
我是 sed 的新手,我根据我的理解创建了下面的 sed 工作流程(如果您发现任何错误,请纠正我)。
因此,模式空间的默认自动打印似乎总是在末尾包含换行符。我的问题是,willp
也包含换行符吗?我有下面的例子。
root@u1804:~# seq 3 | sed -rn 'p'
1
2
3
root@u1804:
Run Code Online (Sandbox Code Playgroud)
这里每个数字末尾的换行符是由 sed 本身添加的(参见图“将换行符添加回模式空间”)。所以看起来p
不会附加换行符。但是,请参阅下面的示例。
root@u1804:~# seq 3 | sed -rn 'x;p;x;p'
1
2
3
root@u1804:~#
Run Code Online (Sandbox Code Playgroud)
这里x
将模式空间与保持空间交换,这将导致模式空间为空。现在p
应用于模式空间(其中没有任何内容)应该不打印任何内容。但根据结果,这里似乎p
打印了一个换行符。在我看来,这是不一致的行为。谁能解释一下吗?
回答你的主要问题:
GNU将在执行命令时sed
附加一个字符,除非输入行缺少终止字符(请参阅下面有关行的说明)。<newline>
p
<newline>
据我所知,sed
的p
标志及其自动打印功能实现了相同的逻辑来输出模式空间:如果<newline>
删除了尾随字符,则将其添加回来;如果删除了尾随字符,则将其添加回来。否则他们不会。
例子:
$ printf '%s\n%s' '4' '5' | sed ';' | hexdump -C # auto-print
00000000 34 0a 35 |4.5|
00000003
Run Code Online (Sandbox Code Playgroud)
$ printf '%s\n%s' '4' '5' | sed -n 'p;' | hexdump -C # no auto-print; p flag
00000000 34 0a 35 |4.5|
00000003
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,对于没有<newline>
字符 ( 0a
) 的输入行,输出中都没有字符 ( )。
关于你的图表:
“将换行符添加回模式空间”可能不准确,因为<newline>
字符未放入模式空间1中。另外,该步骤与选项无关- 但这并不会使图表出错;相反,它可能应该合并到“打印模式空间”中。
不过,我同意你关于文档缺乏清晰度的看法。-n
1您在自己的答案中引用的句子“模式空间的内容被打印到输出流,如果删除了尾部换行符,则将其添加回来”,意味着被附加到流,而不是模式空间。当然,由于模式空间很快就会被清除,所以这是一个非常小的问题<newline>
关于涉及标志的测试x
:
在内部,模式空间和保留空间都是结构,并且“我的尾随<newline>
字符被删除了吗?” 是他们中的一员。我们将其称为chompedsed
(顺便说一句,正如它在源代码中的命名)。
模式空间填充有读取行,其chomped属性取决于该行的终止方式:true
如果它以<newline>
字符结尾,false
否则。另一方面,保留空间被初始化为空,并且其chomped属性仅设置为true
。
因此,当您交换图案空间和保留空间并打印最初作为保留而现在是图案的内容时,<newline>
就会打印一个字符。
示例 - 这些命令具有相同的输出:
$ printf '\n' | sed -n 'p;' | hexdump -C # input is only a <newline>
00000000 0a |.|
00000001
Run Code Online (Sandbox Code Playgroud)
$ printf '%s' '5' | sed -n 'x;p;' | hexdump -C # input has no <newline>
00000000 0a |.|
00000001
Run Code Online (Sandbox Code Playgroud)
(我只简单地浏览了sed
的代码,所以这很可能不准确)。
关于行(从对您的答案的评论开始澄清):
不言而喻,没有终止字符的行<newline>
是一个有问题的概念。引用POSIX:
3.206 行由零个或多个非字符加上一个终止字符组成的
序列。<newline>
<newline>
此外,POSIX定义了一个文本文件:
3.403 文本文件
包含组织成零行或多行的字符的文件。...
最后,POSIXsed
(粗体是我的):
描述
该sed
实用程序是一种流编辑器,应读取一个或多个文本文件,根据编辑命令的脚本进行编辑更改,并将结果写入标准输出。...
不过, GNUsed
在定义其输入时似乎不太严格:
sed
是一个流编辑器。流编辑器用于对输入流(文件或来自管道的输入)执行基本文本转换。...
因此,关于我的第一句话,我们应该考虑到,对于 GNU 来说sed
,读入模式空间的内容不一定是格式良好的文本行。