传送到命令后尾随新行:有任何标准吗?
Trailing new line after piping to a command: is there any standard?
回答 我发现有些程序确实会在字符串末尾添加尾随换行符,而其他程序则不会:
假设我们有字符串 foobar
并用 printf
打印它,这样我们就不会得到额外的新行:
$ printf "foobar" | od -c
0000000 f o o b a r
0000006
或 echo -n
:
$ echo -n "foobar" | od -c
0000000 f o o b a r
0000006
(echo
的默认行为是 return 输出后跟一个换行符,所以 echo "foobar"
returns f o o b a r \n
).
sed
和 cat
都没有添加任何额外的字符:
$ printf "foobar" | sed 's/./&/g' | od -c
0000000 f o o b a r
0000006
$ printf "foobar" | cat - | od -c
0000000 f o o b a r
0000006
而 awk
和 cut
都可以。另外 xargs
和 paste
添加这个尾随的新行:
$ printf "foobar" | cut -b1- | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | awk '1' | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | xargs | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | paste | od -c
0000000 f o o b a r \n
0000007
所以我想知道:为什么会有这种不同的行为? POSIX 对此有什么建议吗?
请注意,我 运行 所有这些都在我的 Bash 4.3.11 中,其余的是:
- GNU Awk 4.0.1
- sed(GNU sed)4.2.2
- cat(GNU 核心工具)8.21
- cut (GNU coreutils) 8.21
- xargs (GNU findutils) 4.4.2
- 粘贴 (GNU coreutils) 8.21
So I was wondering: why is this different behaviour? Is there anything POSIX suggests about this?
一些命令(例如 printf
)是 libc
库调用(例如 printf()
)的简单接口,不会自动添加 \n
。大多数 *NIX 文本处理命令会在最后一行的末尾添加一个 \n
。
从 POSIXv7 的 Definitions 开始,文本行的末尾必须有一个 newline
:
3.206 Line
零个或多个非 <newline>
字符加上一个终止字符的序列。
如果缺少newline
,则变成这样:
3.195 Incomplete Line
文件末尾的一个或多个非 <newline>
字符序列。
一般的想法是可以将文本文件视为记录列表,其中每条记录都以 \n
结尾。换句话说,\n
不是行之间的东西——它是行的一部分。例如,参见 fgets()
函数:\n
始终包含在内,用于识别文本行是否被完整读取的情况。如果最后一行缺少 \n
,则必须进行更多检查才能正确读取文件。
一般来说,只要您的文本文件是由 *NIX programs/scripts 在 *NIX 上创建的,就可以期望最后一行正确终止。但是许多 Java 应用程序以及 Windows 应用程序无法正确或一致地处理该问题。他们不仅经常忘记添加最后一个 \n
,而且还经常错误地将尾随 \n
视为额外的空行。
回答
假设我们有字符串 foobar
并用 printf
打印它,这样我们就不会得到额外的新行:
$ printf "foobar" | od -c
0000000 f o o b a r
0000006
或 echo -n
:
$ echo -n "foobar" | od -c
0000000 f o o b a r
0000006
(echo
的默认行为是 return 输出后跟一个换行符,所以 echo "foobar"
returns f o o b a r \n
).
sed
和 cat
都没有添加任何额外的字符:
$ printf "foobar" | sed 's/./&/g' | od -c
0000000 f o o b a r
0000006
$ printf "foobar" | cat - | od -c
0000000 f o o b a r
0000006
而 awk
和 cut
都可以。另外 xargs
和 paste
添加这个尾随的新行:
$ printf "foobar" | cut -b1- | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | awk '1' | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | xargs | od -c
0000000 f o o b a r \n
0000007
$ printf "foobar" | paste | od -c
0000000 f o o b a r \n
0000007
所以我想知道:为什么会有这种不同的行为? POSIX 对此有什么建议吗?
请注意,我 运行 所有这些都在我的 Bash 4.3.11 中,其余的是:
- GNU Awk 4.0.1
- sed(GNU sed)4.2.2
- cat(GNU 核心工具)8.21
- cut (GNU coreutils) 8.21
- xargs (GNU findutils) 4.4.2
- 粘贴 (GNU coreutils) 8.21
So I was wondering: why is this different behaviour? Is there anything POSIX suggests about this?
一些命令(例如 printf
)是 libc
库调用(例如 printf()
)的简单接口,不会自动添加 \n
。大多数 *NIX 文本处理命令会在最后一行的末尾添加一个 \n
。
从 POSIXv7 的 Definitions 开始,文本行的末尾必须有一个 newline
:
3.206 Line
零个或多个非
<newline>
字符加上一个终止字符的序列。
如果缺少newline
,则变成这样:
3.195 Incomplete Line
文件末尾的一个或多个非
<newline>
字符序列。
一般的想法是可以将文本文件视为记录列表,其中每条记录都以 \n
结尾。换句话说,\n
不是行之间的东西——它是行的一部分。例如,参见 fgets()
函数:\n
始终包含在内,用于识别文本行是否被完整读取的情况。如果最后一行缺少 \n
,则必须进行更多检查才能正确读取文件。
一般来说,只要您的文本文件是由 *NIX programs/scripts 在 *NIX 上创建的,就可以期望最后一行正确终止。但是许多 Java 应用程序以及 Windows 应用程序无法正确或一致地处理该问题。他们不仅经常忘记添加最后一个 \n
,而且还经常错误地将尾随 \n
视为额外的空行。