为什么`export`替换失败会失败,但命令失败会失败?

时间:2019-06-06 02:41:04

标签: bash language-lawyer

众所周知,export masks the return value of command substitutions in its variable assignments。但是,有趣的是 export不会掩盖失败替换的返回值:

$ (set -eu; export FOO="$(bad_command)"); echo $?
bash: bad_command: command not found
0
$ (set -eu; export FOO="${bad_variable}"); echo $?
bash: bad_variable: unbound variable
1
$ (set -eu; export FOO="${}"); echo $?  # bad substitution
bash: ${}: bad substitution
1

dash中的类似行为。)

规范的哪一部分表示命令失败 替代不会通过export传播,但会失败 参数扩展吗?

man bash(GNU Bash 4.4)中的相关部分:

  
set -u
     

处理未设置的变量和参数,而不是   特殊参数“ @”和“ *”作为执行参数时的错误   扩张。如果尝试对未设置的变量进行扩展,或者   参数,外壳程序会显示一条错误消息,如果不是交互式的,   以非零状态退出。

  
export [-fn] [name[=word]] ...
export -p
     

提供的names被标记为自动导出到   后续执行命令的环境。如果-f选项是   给定的名称是指功能。如果没有给出名称,或者   提供了-p选项,所有导出变量的名称列表为   印刷。 -n选项导致从中删除导出属性   每个name。如果变量名后跟=word,则值   变量设置为wordexport返回退出状态0   除非遇到无效的选项,否则names之一不是   有效的shell变量名称,或者-f附带了name   不是功能。

-我在这里看不到任何可以区分这两种情况的内容。 具体来说,export只是说变量“的值已设置 到“ word”,这表明它经历了正常的扩展 处理(确实如此)而无需特殊处理。

POSIX规范参考:

1 个答案:

答案 0 :(得分:2)

这两种情况都不完全符合export

命令替换只是变成命令参数数组中的文本(是否为空)。 Unix流程模型没有任何机制来中继文本是否来自程序,或者该程序是否成功。

这意味着在运行foo var="$(true)" vs foo var="$(false)" vs foo var=""时,编写外部命令的行为是不可能的,并且像export这样的shell内置程序通常遵循相同的命令行为以便于实施。

使用set -u和未设置的变量,该命令根本不会运行。如果在构建参数数组时遇到此条件,则外壳程序仅跳过执行,而是报告失败。命令从未选择忽略这种失败,因为从未咨询过它。

如果在参数数组的构造过程中命令替换失败,则可以实现一种新的shell模式,该模式类似地跳过执行并报告失败,但这不是传统功能,因此不在POSIX规范中。 / p>