有人可以向我解释一下吗:
$ type blah
bash: type: blah: not found
$ echo $?
1
$ bash --init-file <( echo "type blah; echo $?" )
bash: type: blah: not found
0
为什么初始化脚本中的返回值与交互式 shell 中的返回值不同?
编辑交互式 shell 的初始化脚本又有所不同:
$ bash --init-file <( echo "type blah; echo $?" ) -i
bash: type: blah: not found
2
Bash 版本是 4.4.12。
答案1
问题是$?
正在评估前它作为参数传递给外部echo
命令。因此,您运行的是相当于:
bash --init-file <( echo "type blah; echo 0" ) -i
您可以使用模式来查看此内容set -x
,它将显示与已执行命令等效的内容:
$ bash --init-file <( echo "type blah; echo $?" )
+ bash --init-file /dev/fd/63
++ echo 'type blah; echo 0'
bash: type: blah: not found
0
注意第三行,++ echo 'type blah; echo 0'
--$?
在传递给命令echo
(然后传递给新的 shell 执行)之前已经扩展了。顺便说一句,这意味着它实际上显示的是上次运行的命令的结果前这个:
$ curl http://notarealdomain.example.com/
curl: (6) Could not resolve host: notarealdomain.example.com
$ bash --init-file <( echo "type blah; echo $?" )
bash: type: blah: not found
6
请注意,打印的状态“6”是curl
表示无法解析的主机错误的代码。
无论如何,解决方案很简单:使用单引号来延迟评估$?
:
$ bash --init-file <( echo 'type blah; echo $?' )
bash: type: blah: not found
1
答案2
先回答
- 初始化脚本与返回值无关。
- 进程替代
<(...)
才是真正的原因。
解释
[证明1]现在尝试下面的命令。它没有选项--init-file
,但输出相同(带有一些简单的打印)。
(exit 10)
bash <( echo "type blah; echo $?" )
[证明2]尝试以下命令,并改变第一个命令中的数字,您将发现更多不同的返回值。
(exit 117)
bash --init-file <( echo "type blah; echo $?" )
[证明3]你看到什么输出?
(exit 23)
cat <( echo "type blah; echo $?" )
我想你可以通过上面的3个证明来理解答案1。那么答案2呢?
如果你只是输入简单的命令echo "type blah; echo $?"
来运行它,你期望得到什么结果?你期望它会打印type blah; echo <num>
,其中 是<num>
最后一个命令的返回值。对吧?我们都知道 将$?
被替换为数字,因为我们都知道 bash 会对 进行参数扩展$?
。
流程替换也是一样的<(...)
。
在 Bash 中,出现在进程替换中的命令<(...)
将在子 shell 中调用。子 shell 也是一个 shell(Bash)。因此对于命令echo "type blah; echo $?"
,您在子 shell 中将获得与在当前 shell 中直接运行完全相同的结果,这意味着子 shell 也会对 进行参数扩展$?
,就像 bash 所做的那样。
因此当您运行 时bash --init-file <(echo "type blah; echo $?")
,init-script 文件的内容实际上是type blah; echo <num>
而不是type blah; echo $?
。
更深
虽然在进程替换中<(echo "type blah; echo $?")
被子$?
shell 扩展了,但是它的值还是受到当前shell的影响,子shell 中的 的值?
和当前shell 中的 的值是一样的。
参见证明2,第一个命令为(exit 117)
,它使当前shell中的 的值$?
变为117,但在子shell中它也扩展为117。
这是因为出现在进程替换中的命令<(...)
是在子 shell 环境中调用的,而该环境是复制当前 shell 环境。
因此,这解释了您的问题,如果您-i
在命令中放入 option ,则会显示不同的返回值。这不是 option 带来的区别-i
。这是因为在该命令之前,您肯定会执行另一个返回 2 的命令。
更多单词
事实上,还有另外三种形式,其工作方式与 bash 中的进程替换相同。
- 命令替换
$(...)
或`...`
- 用括号分组的命令
(...)
- 管道中的内置命令
<builtin cmd> | ...
或... | <builtin cmd>
或<builtin cmd> | <builtin cmd>