Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“结尾处的换行符”$"("")";在shell脚本中删除。为什么?_Shell_Unix_Scripting_Ksh - Fatal编程技术网

“结尾处的换行符”$"("")";在shell脚本中删除。为什么?

“结尾处的换行符”$"("")";在shell脚本中删除。为什么?,shell,unix,scripting,ksh,Shell,Unix,Scripting,Ksh,有人能解释为什么这两个命令的输出不同吗 $ echo "NewLine1\nNewLine2\n" NewLine1 NewLine2 <-- Note 2nd newline here $ echo "$(echo "NewLine1\nNewLine2\n")" NewLine1 NewLine2 $ <-- No second newline $echo“NewLine1\nNew

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

$ echo "NewLine1\nNewLine2\n"
NewLine1
NewLine2
                         <-- Note 2nd newline here
$ echo "$(echo "NewLine1\nNewLine2\n")"
NewLine1
NewLine2
$                        <-- No second newline
$echo“NewLine1\nNewLine2\n”
新闻1
新闻2

命令替换将删除每一个后续换行符

删除一个是有道理的。例如:

basename foo/bar
输出
条\n
。在:

var=$(basename foo/bar)
您希望
$var
包含
bar
,而不是
bar\n

然而在

var=$(basename $'foo/bar\n')
您希望
$var
包含
bar\n
(毕竟,换行符与Unix上文件名中的任何字符一样有效)。但是,所有shell都会删除所有尾随的换行符。这一缺陷出现在原来的伯恩外壳中,甚至修复了伯恩大部分缺陷的
rc
也没有修复该缺陷。(尽管
rc
具有
``({cmd}
语法,不去除任何换行符)

在POSIX Shell中,要解决此问题,可以执行以下操作:

var=$(basename -- "$file"; echo .)
var=${var%??}
尽管您将失去
basename
的退出状态。您可以通过以下方式进行修复:

var=$(basename -- "$file" && echo .) && var=${var%??}
${var%??}
将删除最后两个字符。第一个是我们在上面添加的
,第二个是由
basename
添加的一个换行符,我们不再删除任何换行符,因为其他换行符(如果有的话)将是我们想要获取其基的文件名的一部分,所以我们确实需要它们

在没有
${var%x}
运算符的Bourne shell中,您必须以一种漫长而复杂的方式来解决它。

因为并且一直都像在Bourne shell中一样:

2.6.3命令替换

命令替换允许替换命令的输出 代替命令名本身。命令替换应发生 当命令按如下方式封闭时:

$(命令)

或(后引版本):

`命令`

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

保留最后换行的一种方法是

视觉:

$x=“$(whoami;echo x)”;printf'\n'$x'${x%x}”
但为什么要删除尾随的新行呢?因为很多时候你都希望这样。我也在用perl编程,我无法计算读取一行或一个变量然后需要切掉换行符的次数:

while (defined ($string = <>)) {
    chop $string;
    frobnitz($string);
} 
while(已定义($string=)){
切掉$string;
弗罗布尼茨($string);
} 

如果没有删除换行符,则构造如下:

x="$(pwd)/filename"
不会有效地工作,但编写Unix的人更喜欢有用的行为


很长一段时间以前(比如1983年,也许1984年),有一次,我在Unix的一个特定变体上遇到了一个shell更新,它没有删除后面的换行符。它破坏了所有地方的脚本。它很快就被修复了。

回声的本质是消耗空白。我现在没有时间进行测试,但您在问题测试中引用的dbl可能没有达到您的想法。也许
echo“$(echo\'NewLine1\nNewLine2\n\””
会起作用。祝您好运。谢谢,但您不需要在“$(..”语句的括号内转义双引号。它被视为一个新命令。这是使用$(…)而不是滴答声的优点之一。上面的问题也可以通过使用记号来重现。它的记录行为:()-“…命令的标准输出,删除任何尾随的换行符”。为了避免这种情况,您可能需要将输出重定向到临时文件,然后使用该文件。这是一个很好的解释。这有点令人沮丧,因为我有一个脚本,其中“$(…)”语句末尾的新行对我很重要。就像我上面所说的,我可能会附加一个随机字母,然后将其去掉。@glennjackman:您应该将其作为答案发布。
VAR=“$(command)x”
不会保留最后的换行符,因为是命令替换将其去掉。@sch Oops,已修复。谢谢你的提醒。
while (defined ($string = <>)) {
    chop $string;
    frobnitz($string);
} 
x="$(pwd)/filename"