bash - 为什么 `export` 会因替换错误而失败,但不会因命令失败而失败?
问题描述
众所周知,export
在其变量 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
执行参数扩展时,将未设置的变量和特殊参数“@”和“*”以外的参数视为错误。如果尝试对未设置的变量或参数进行扩展,shell 会打印一条错误消息,如果不是交互式的,则以非零状态退出。
和
export [-fn] [name[=word]] ... export -p
提供
names
的标记为自动导出到随后执行的命令的环境。如果-f
给出了选项,则名称指的是函数。如果没有给出名称,或者-p
提供了选项,则打印所有导出变量的名称列表。该-n
选项会导致从每个name
. 如果变量名后跟=word
,则变量的值设置为word
。export
返回退出状态 0,除非遇到无效选项,其中之一names
不是有效的 shell 变量名,或者-f
提供的name
不是函数。
——我在这里看不到任何可以区分这两种情况的东西。特别是,export
只是说变量的值“设置为” word
,这表明它经历了正常的扩展过程(它确实如此)而没有特殊处理。
POSIX 规范参考:
解决方案
这两种情况都不是真正的export
命令替换只是成为命令参数数组中的文本(空或非空)。Unix 进程模型没有任何机制来传递文本是否来自程序,或者该程序是否成功。
foo var="$(true)"
这意味着当您运行vs foo var="$(false)"
vsfoo var=""
和 shell 内置命令时,不可能编写行为不同的外部命令,就像export
传统上遵循相同的行为以便于实现一样。
使用set -u
和未设置变量,该命令根本不会运行。如果在构建参数数组时遇到这种情况,shell 会简单地跳过执行,并报告失败。一个命令不能选择忽略这样的失败,因为它从来没有被咨询过。
如果在参数数组的构造过程中命令替换失败,当然可以实现一个新的 shell 模式,类似地跳过执行并报告失败,但这不是传统功能,因此不在 POSIX 规范中。
推荐阅读
- python - FileDialog 方法的 filetypes 属性在 windows10 上没有文件扩展名
- django - Django 缓存什么时候过期?
- javascript - Mup 部署验证失败,172.17.0.4 端口 80:连接被拒绝
- algorithm - 如何对一组数字进行排序以产生分散的数字?
- javascript - 如何在ng-if中进行均衡?(角JS)
- javascript - 在 AnimateCC 中,当我从库中添加一个按钮时,它不起作用,而是连续运行所有状态
- amazon-cloudformation - 在 cloudformation 中使用 s3 相对路径
- c# - 将位置从 3D 相机转换为 2D 相机
- macos - 在 MacOS 上通过 Pycharm 从 iterm2 打开超链接文件
- reactjs - React + Electron + react-hot-loader + react-router + webpack-dev-server