这两个命令具有相同的结果是有意义的:

$ if 1; then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

$ if $(printf 1); then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

因为$(printf "1")是在1中执行1之前打印的。
不过,鉴于此,我不明白为什么这些会产生不同的结果:
$ if ""; then printf "success\n"; else printf "failure\n"; fi
-bash: : command not found
failure

$ if ; then printf "success\n"; else printf "failure\n"; fi
-bash: syntax error near unexpected token `;'

$ if $(printf ""); then printf "success\n"; else printf "failure\n"; fi
success

为什么if输出的空字符串会被区别于第一个命令中显式编码为$(printf "")的空字符串或第二个命令中缺少的参数?在最终命令中执行的是什么,并被发现成功了,为什么?
更新-确保我得到它!
因此,将@chepner's answer应用到上面的脚本中,我添加了解释(如果我有任何错误,请纠正我):
$ if 1; then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

shell解析"",看到它希望是命令但实际上是数字if 1;,因此失败“command not found”
$ if $(printf 1); then printf "success\n"; else printf "failure\n"; fi
-bash: 1: command not found
failure

shell解析1,看到它希望成为命令的东西,if $(printf 1);,成功执行它,输出1。shell看到有东西被输出了($(printf 1)),并且给出了这个上下文中的任何输出,shell希望“something”也是一个它应该能够执行的命令,但实际上是数字1,因此失败了“command not found”。
$ if ""; then printf "success\n"; else printf "failure\n"; fi
-bash: : command not found
failure

shell解析1,看到它希望是命令但实际上是字符串“”的内容,因此失败“找不到命令”
$ if ; then printf "success\n"; else printf "failure\n"; fi
-bash: syntax error near unexpected token `;'

shell解析if "";,在该上下文中找不到它期望找到的命令,因此失败“语法错误”
$ if $(printf ""); then printf "success\n"; else printf "failure\n"; fi
success

shell解析if ;,看到它希望成为命令的东西,if $(printf "");,成功执行它,输出shell所接受的任何东西,因此没有新的命令执行,因此将它运行的最后一个命令的成功退出状态($(printf ""))应用到一个整体的条件中,这样就成功了。

最佳答案

简而言之:在shell尝试对其执行命令查找之前,在应用于命令替换的分词过程中,printf输出的空字符串将消失。
当shell读取其输入时,它需要在计算命令之前读取并解析整个命令。
读取if之后,解析器将在执行任何计算之前解析整个if语句。下一步它需要一个复合列表作为条件。不过,复合列表不能以分号开头,因此当解析器看到if ;时,它会立即发出错误信号。
略过一点细节,就足以说明字符串$(print "")确实解析为一个复合列表。还不需要计算,因此if $(print ""); then ...成功解析。
解析完成后,现在shell实际上必须对其求值。这样做的过程记录在bash手册页的“简单命令扩展”下,全文引用如下,并突出显示相关段落:
简单命令扩展
当执行一个简单的命令时,shell执行以下扩展、分配和重定向,从左到
正确的。
解析器标记为变量赋值(在命令名之前)和重定向的单词是
保存以供以后处理-
惯性导航与制导。
非变量赋值或重定向的单词将展开。如果扩展后仍有任何单词,则
第一个词被认为是
命令的名称和剩余的单词是参数。
重定向的执行如上重定向下所述。
在每个变量赋值中,后面的文本将进行颚化符扩展、参数扩展、命令替换,
算术展开式,
在分配给变量之前移除引号。
如果没有命令名结果,变量分配将影响当前shell环境。否则,变量将添加到
环境
执行的命令不会影响当前的shell环境。如果任何赋值尝试将值赋给
只读变量,
发生错误,命令以非零状态退出。
如果没有命令名结果,则会执行重定向,但不会影响当前的shell环境。重定向错误导致
命令
非零状态退出。
如果在展开后还有一个命令名,则执行过程如下所述。否则,命令退出。如果其中一个
扩张论-
获得一个命令替换,命令的退出状态是执行最后一个命令替换的退出状态。如果
没有com-
Mand替换,命令以零状态退出。
因此,$(print "")成功,但扩展为一个空单词列表。因此,使用命令替换的退出状态立即返回if语句的条件“执行”,从而得到真正的分支。

关于bash - 为什么在条件中将打印的null与文字的null区别对待?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56160516/

10-16 20:32