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: <[email protected]>.
root@u1804:~#
我是 sed 的新手,我根据我的理解创建了下面的 sed 工作流程(如果您发现任何错误,请纠正我)。
因此,模式空间的默认自动打印似乎总是在末尾包含换行符。我的问题是,willp
也包含换行符吗?我有下面的例子。
root@u1804:~# seq 3 | sed -rn 'p'
1
2
3
root@u1804:
这里每个数字末尾的换行符是由 sed 本身添加的(参见图“将换行符添加回模式空间”)。所以看起来p
不会附加换行符。但是,请参阅下面的示例。
root@u1804:~# seq 3 | sed -rn 'x;p;x;p'
1
2
3
root@u1804:~#
这里x
将模式空间与保持空间交换,这将导致模式空间为空。现在p
应用于模式空间(其中没有任何内容)应该不打印任何内容。但根据结果,这里似乎p
打印了一个换行符。在我看来,这是不一致的行为。谁能解释一下吗?
答案1
回答你的主要问题:
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
$ printf '%s\n%s' '4' '5' | sed -n 'p;' | hexdump -C # no auto-print; p flag
00000000 34 0a 35 |4.5|
00000003
在这两种情况下,对于没有字符 ( ) 的输入行,输出中都没有字符<newline>
( )。0a
关于你的图表:
“将换行符添加到模式空间”可能不准确,因为<newline>
未放置字符在模式空间1 .另外,该步骤与选项无关-n
- 但这不会使图表错误的;相反,它可能应该合并到“打印模式空间”中。
不过,我同意你关于文档缺乏清晰度的看法。
1你引用的那句话在你自己的回答中,“模式空间的内容被打印到输出流,如果删除了尾部换行符,则将其添加回来”,意味着 被<newline>
附加到流,而不是模式空间。当然,由于模式空间很快就会被清除,所以这是一个非常小的问题
关于涉及旗帜的测试x
:
在内部,模式空间和保留空间都是结构,并且“我的尾随<newline>
字符被删除了吗?”是他们中的一员。我们将称之为咀嚼过的sed
(顺便说一句,正如它在源代码中所命名的那样)。
模式空间充满了读取行及其咀嚼过的属性取决于该行的终止方式:true
如果它以字符结尾<newline>
,false
否则。另一方面,保持空间被初始化为空并且它的咀嚼过的属性刚刚设置为true
。
因此,当您交换图案空间和保留空间并打印最初作为保留而现在是图案的内容时,<newline>
就会打印一个字符。
示例 - 这些命令具有相同的输出:
$ printf '\n' | sed -n 'p;' | hexdump -C # input is only a <newline>
00000000 0a |.|
00000001
$ printf '%s' '5' | sed -n 'x;p;' | hexdump -C # input has no <newline>
00000000 0a |.|
00000001
(我只简单地浏览了sed
的代码,所以这很可能不准确)。
关于行(澄清从评论开始您的答案):
不言而喻,线没有终止<newline>
字符是一个有问题的概念。引用POSIX:
3.206线
<newline>
零个或多个非字符加上终止字符 的序列<newline>
。
此外,POSIX定义一个文本文件:
3.403 文本文件
包含组织成零行或多行的字符的文件。 ...
最后,POSIX关于sed
(粗体我的):
描述
该sed
实用程序是一个流编辑器,可以读取一个或多个文本文件,根据编辑命令的脚本进行编辑更改,并将结果写入标准输出。 ...
GNUsed
不过,在定义其输入时似乎不太严格:
sed
是一个流编辑器。流编辑器用于对输入流(文件或来自管道的输入)执行基本文本转换。 ...
因此,关于我的第一句话,我们应该考虑到,对于 GNU 来说sed
,读入模式空间的内容不一定是格式良好的文本行。
答案2
答案3
在 GNU sed 中:p
仅当源文本中存在换行符时,该命令才会添加尾随换行符(当放置在模式空间中时,该换行符会从输入中删除),但是还如果将其他文本打印到同一流,则添加前导新行。
仅在输入中可能会缺少尾随换行符最后的线。
$ printf 'abc' | od -An -c
a b c # no newline.
$ printf 'abc' | sed '' | od -An -c
a b c # also no newline.
$ printf 'abc' | sed -n 'p' | od -An -c
a b c # still no newline.
$ printf 'abc' | sed -n 'p;p' | od -An -c
a b c \n a b c # leading newline added.
只打印最后一行,其中会有一个新行仅有的如果源文件的最后一行已经有换行符:
$ printf 'abc\ndef' | sed -n '$p' | od -An -c
d e f
来自信息 sed:
---------- 脚注 ----------
(1) 实际上,如果 'sed' 打印一行没有终止换行符,那么一旦将更多文本发送到同一输出流,它仍然会打印缺失的换行符,这给出了“最不预期的惊喜”,即使它没有使“sed -n p”等命令与“cat”完全相同。
其他一些 sed 版本可能会添加尾随换行和/或发出警告。