Bash 脚本 - 初始化脚本中的“type”返回值不同

Bash 脚本 - 初始化脚本中的“type”返回值不同

有人可以向我解释一下吗:

$ 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. 初始化脚本与返回值无关。
  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 中的进程替换相同。

  1. 命令替换$(...)`...`
  2. 用括号分组的命令(...)
  3. 管道中的内置命令 <builtin cmd> | ...... | <builtin cmd><builtin cmd> | <builtin cmd>

相关内容