最后的新行"$(....)"在shell脚本中被删除.为什么?

Hen*_*ley 5 unix shell scripting ksh

有人能解释为什么这两个命令的输出不同吗?

$ echo "NewLine1\nNewLine2\n"
NewLine1
NewLine2
                         <-- Note 2nd newline here
$ echo "$(echo "NewLine1\nNewLine2\n")"
NewLine1
NewLine2
$                        <-- No second newline
Run Code Online (Sandbox Code Playgroud)

有没有什么好办法可以在"$(....)"中将新行保留在输出的末尾?我想过只是添加一个虚拟字母并删除它,但我很想知道为什么这些新线条会消失.

Jen*_*ens 4

因为这就是 POSIX 指定的内容,并且在 Bourne shell 中一直如此:

2.6.3 命令替换

命令替换允许用命令的输出来替换命令名称本身。当命令包含如下时,将发生命令替换:

$(命令)

或(反引号版本):

`命令`

shell 应通过在子 shell 环境中执行命令(请参阅 Shell 执行环境)并用命令的标准输出替换命令替换(命令文本加上“$()”或反引号)来扩展命令替换,删除替换末尾的一个或多个 <newline> 字符的序列。输出结束前嵌入的<newline>字符不得被删除;但是,它们可能会被视为字段分隔符并在字段拆分期间被消除,具体取决于 IFS 的值和有效的引用。如果输出包含任何空字节,则行为未指定。

保留最终换行符的一种方法是

VAR="$(command; echo x)"   # Append x to keep newline(s).
VAR=${VAR%x}               # Chop x.
Run Code Online (Sandbox Code Playgroud)

可见:

$ x="$(whoami; echo x)" ; printf '<%s>\n' "$x" "${x%x}"
<user
x>
<user
>
Run Code Online (Sandbox Code Playgroud)

但为什么要删除尾随换行符呢?因为很多时候你都希望如此。我也在 perl 中编程,我无法计算读取一行或变量然后需要截断换行符的次数:

while (defined ($string = <>)) {
    chop $string;
    frobnitz($string);
} 
Run Code Online (Sandbox Code Playgroud)

  • `VAR="$(command)x"` 不会保留最终的换行符,因为命令替换会删除它们。 (2认同)