分配类似于具有退出状态的命令,除了何时有命令替换?


10

请参阅以下示例及其在POSIX Shell中的输出:

  1. false;echo $?false || echo 11
  2. false;foo="bar";echo $?foo="bar" && echo 00
  3. foo=$(false);echo $?foo=$(false) || echo 11
  4. foo=$(true);echo $?foo=$(true) && echo 00

正如在/programming/6834487/what-is-the-variable-in-shell-scripting中投票最高的答案所提到的:

$? 用于查找最后执行的命令的返回值。

在这种情况下,这可能有点误导,因此让我们获取POSIX定义,该定义也在该线程的帖子中被引用:

?扩展到最新管道的小数退出状态(请参见管道)。

因此,它仿佛是一次分配本身算作一个命令(或者说管道部分)以零退出值,但其应用之前分配的右侧(例如,在我的例子命令替换调用这里)。

我从实际的角度看这种行为是有道理的,但对我而言,分配本身按该顺序进行计数似乎有点不寻常。也许要弄清楚为什么对我来说很奇怪,让我们假设赋值是一个函数:

ASSIGNMENT( VARIABLE, VALUE )

foo="bar"会是

ASSIGNMENT( "foo", "bar" )

并且foo=$(false)会像

ASSIGNMENT( "foo", EXECUTE( "false" ) )

这意味着EXECUTE运行,然后运行,但这仍然是重要的状态。 ASSIGNMENTEXECUTE

我的评估是否正确,或者我误会/遗漏了什么?这些是我将这种行为视为“奇怪”的正确原因吗?


1
抱歉,但我不清楚您发现什么奇怪。
库萨兰达

1
@Kusalananda也许这有助于告诉您它始于我问自己:“为什么false;foo="bar";echo $?当最后一个执行的真实命令false为时总是返回0 ?” 从根本上说,赋值在退出代码方面表现得很特别。它们的退出代码始终为0,除非不是由于某种原因(作为赋值右侧的一部分而运行)而退出的。
phk

Answers:


10

作业的退出状态很奇怪。分配失败的最明显方法是标记了目标变量readonly

$ err(){ echo error ; return ${1:-1} ; }
$ PS1='$? $ '
0 $ err 42
error
42 $ A=$(err 12)
12 $ if A=$(err 9) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
E=9 ?=0
0 $ readonly A
0 $ if A=$(err 10) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
A: is read only
1 $

注意,没有使用if语句的true或false路径,分配失败会停止执行整个语句。如果分配失败,则POSIX模式下的bash和ksh93和zsh都将中止脚本。

在此引用POSIX标准

没有命令名称但包含命令替换的命令具有外壳程序执行的最后命令替换的退出状态。

这正是外壳语法所涉及的部分

 foo=$(err 42)

来自simple_command(简单命令→cmd_prefix→ASSIGNMENT_WORD)。因此,如果分配成功,则除非涉及命令替换,否则退出状态为零,在这种情况下,退出状态为最后一个的状态。如果分配失败,则退出状态为非零,但您可能无法捕获它。


1
为了增加您的答案,这是来自不同线程的答案,在该线程上引用了最新的POSIX标准,结论基本上是相同的:unix.stackexchange.com/a/270831/117599
phk

4

你说,

…似乎分配本身算作一条命令…出口值为零,但适用于该分配的右侧(例如,命令替换调用…)

这不是一个糟糕的方法。但这有点过分简化。的整体退货状态

A = $(cmd 1)B = $(cmd 2)C = $(cmd 3)D = $(cmd 4)E = mc 2
是的退出状态。在之后出现的分配分配不会整体退出状态设置为0。cmd4E=D=

同样,如icarus所 指出,变量可以设置为只读。考虑以icarus为例的以下变体:

$ err() { echo "stdout $*"; echo "stderr $*" >&2; return ${1:-1}; }
$ readonly A
$ Z=$(err 41 zebra) A=$(err 42 antelope) B=$(err 43 badger)
stderr 41 zebra
stderr 42 antelope
bash: A: readonly variable
$ echo $?
1
$ printf "%s = %s\n" Z "$Z" A "$A" B "$B"
Z = stdout 41 zebra
A =
B =
$

即使A为只读,bash也会在A=— 右边执行命令替换,然后由于A是只读而中止命令。这进一步与您的解释相矛盾,即该分配的退出值适用于该分配的右侧。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.