当打印包含换行符的变量时,为什么最后一个换行符被删除?

当打印包含换行符的变量时,为什么最后一个换行符被删除?

file.txt 的内容(没有什么奇怪的,POSIX 定义的文本文件)

iguana
gecko
anole

示例脚本:

#!/bin/sh

string="$(cat file.txt)"

printf '%s' "$string"

示例输出:

[coolguy@somemachine ~]$ ./script.sh
iguana
gecko
anole[coolguy@somemachine ~]$

最后一个换行符发生了什么?为什么除了最后一个保留之外,所有的都是换行符?如果已经有换行符,我们似乎不必使用 echo 来添加换行符。

答案1

这不是打印,而是命令替换。它被定义为这样做。来自POSIX 描述:

shell 应通过在子 shell 环境中执行命令并将命令替换替换为命令的标准输出来扩展命令替换,删除替换末尾的一个或多个 {newline} 字符的序列

请注意,它删除了全部尾随换行符,而不只是一个。

在一种常见的情况下,您可以使用命令替换来捕获单行输出,例如osrev=$(uname -r).这些实用程序通常会打印尾随换行符,以方便用户在命令行上使用。但在 shell 脚本中,您可能希望将该字符串用作另一个字符串的一部分,例如文件名:filename=blahblah-$osrev.dat。在这种情况下,尾随的换行符只会带来麻烦。

当然,无论如何,普通文本echo都会添加最后的换行符。


如果您希望变量中的文件内容按原样存在,则常见的解决方法是在命令替换中添加额外的字符,然后将其删除:

printf "foo\nbar\n\n" > file
string=$(cat file; echo x)
string=${string%x}
printf '%q\n' "$string"

输出$'foo\nbar\n\n',显示两个尾随换行符。


根据您打算如何处理数据,可能还有其他方法。例如,如果您碰巧想逐行处理文件,则可以使用while read循环或 Bash 。mapfile

相关内容