[英]Exit code of variable assignment to command substitution in Bash
I am confused about what error code the command will return when executing a variable assignment plainly and with command substitution:当简单地执行变量赋值和命令替换时,我对命令将返回什么错误代码感到困惑:
a=$(false); echo $?
It outputs 1
, which let me think that variable assignment doesn't sweep or produce new error code upon the last one.它输出
1
,这让我认为变量赋值不会清除最后一个错误代码或产生新的错误代码。 But when I tried this:但是当我尝试这个时:
false; a=""; echo $?
It outputs 0
, obviously this is what a=""
returns and it override 1
returned by false
.它输出
0
,显然这是a=""
返回的内容,它覆盖了false
返回的1
。
I want to know why this happens, is there any particularity in variable assignment that differs from other normal commands?我想知道为什么会这样,变量赋值有什么特殊性不同于其他普通命令吗? Or just be cause
a=$(false)
is considered to be a single command and only command substitution part make sense?或者只是因为
a=$(false)
被认为是单个命令并且只有命令替换部分才有意义?
-- UPDATE -- - 更新 -
Thanks everyone, from the answers and comments I got the point "When you assign a variable using command substitution, the exit status is the status of the command."谢谢大家,从答案和评论中我明白了“当您使用命令替换分配变量时,退出状态就是命令的状态。” (by @Barmar), this explanation is excellently clear and easy to understand, but speak doesn't precise enough for programmers, I want to see the reference of this point from authorities such as TLDP or GNU man page, please help me find it out, thanks again!
(by @Barmar),这个解释非常清楚易懂,但是speak对程序员来说不够精确,我想看看TLDP或GNU手册页等权威人士对这一点的参考,请帮助我找到它出来了,再次感谢!
Upon executing a command as $(command)
allows the output of the command to replace itself . 在执行命令时,
$(command)
允许$(command)
的输出替换自身 。
When you say: 当你说:
a=$(false) # false fails; the output of false is stored in the variable a
the output produced by the command false
is stored in the variable a
. 命令
false
产生的输出存储在变量a
。 Moreover, the exit code is the same as produced by the command. 此外,退出代码与命令生成的相同。
help false
would tell: help false
会告诉:
false: false
Return an unsuccessful result.
Exit Status:
Always fails.
On the other hand, saying: 另一方面,说:
$ false # Exit code: 1
$ a="" # Exit code: 0
$ echo $? # Prints 0
causes the exit code for the assignment to a
to be returned which is 0
. 导致该工作分配的退出代码到
a
要返回其为0
。
EDIT: 编辑:
Quoting from the manual : 引自手册 :
If one of the expansions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed.
如果其中一个扩展包含命令替换,则该命令的退出状态是执行的最后一个命令替换的退出状态。
Quoting from BASHFAQ/002 : 引自BASHFAQ / 002 :
How can I store the return value and/or output of a command in a variable?
如何在变量中存储命令的返回值和/或输出?
...
...
output=$(command)
status=$?
The assignment to
output
has no effect oncommand
's exit status, which is still in$?
对
output
的赋值对command
的退出状态没有影响,退出状态仍在$?
.。
Note that this isn't the case when using local
within a function. 请注意,在函数中使用
local
时不是这种情况。 Which is subtly different behavior than described in the the accepted answer, and the posted link here: http://mywiki.wooledge.org/BashFAQ/002 这是与接受的答案中描述的微妙不同的行为,以及此处发布的链接: http : //mywiki.wooledge.org/BashFAQ/002
Take this bash script for example: 以这个bash脚本为例:
#!/bin/bash
function funWithLocalVar() {
local output="$(echo "Doing some stuff.";exit 1)"
local exitCode=$?
echo "output: $output"
echo "exitCode: $exitCode"
}
function funWithoutLocalVar() {
output="$(echo "Doing some stuff.";exit 1)"
local exitCode=$?
echo "output: $output"
echo "exitCode: $exitCode"
}
funWithLocalVar
funWithoutLocalVar
Here is the output of this: 这是这个的输出:
nick.parry@nparry-laptop1:~$ ./tmp.sh
output: Doing some stuff.
exitCode: 0
output: Doing some stuff.
exitCode: 1
Maybe nobody cares, but I did. 也许没有人关心,但我做到了。 It took me a minute to figure out why my status code was always 0 when it clearly wasn't sometimes.
我花了一分钟时间弄清楚为什么我的状态代码总是为0时显然不是。 Not 100% clear why.
不是100%明白为什么。 But just knowing this helped.
但只知道这有帮助。
I came across the same problem yesterday (Aug 29 2018). 我昨天(2018年8月29日)遇到了同样的问题。
In addition to local
mentioned in Nick P.'s answer and @sevko's comment in the accepted answer , declare
in global scope also has the same behavior. 除了
local
提到的Nick P.的答案和@ sevko在接受的答案中的评论, declare
在全球范围内也有相同的行为。
Here's my Bash code: 这是我的Bash代码:
#!/bin/bash
func1()
{
ls file_not_existed
local local_ret1=$?
echo "local_ret1=$local_ret1"
local local_var2=$(ls file_not_existed)
local local_ret2=$?
echo "local_ret2=$local_ret2"
local local_var3
local_var3=$(ls file_not_existed)
local local_ret3=$?
echo "local_ret3=$local_ret3"
}
func1
ls file_not_existed
global_ret1=$?
echo "global_ret1=$global_ret1"
declare global_var2=$(ls file_not_existed)
global_ret2=$?
echo "global_ret2=$global_ret2"
declare global_var3
global_var3=$(ls file_not_existed)
global_ret3=$?
echo "global_ret3=$global_ret3"
The output: 输出:
$ ./declare_local_command_substitution.sh 2>/dev/null
local_ret1=2
local_ret2=0
local_ret3=2
global_ret1=2
global_ret2=0
global_ret3=2
Note the values of local_ret2
and global_ret2
in the output above. 请注意上面输出中的
local_ret2
和global_ret2
的值。 The exit codes are overwritten by local
and declare
. 退出代码被
local
和declare
覆盖。
My Bash version: 我的Bash版本:
$ echo $BASH_VERSION
4.4.19(1)-release
(not an answer to original question but too long for comment) (不是原始问题的答案,但评论太长)
Note that export A=$(false); echo $?
注意
export A=$(false); echo $?
export A=$(false); echo $?
outputs 0! 输出0! Apparently the rules quoted in devnull's answer no longer apply.
显然, devnull答案中引用的规则不再适用。 To add a bit of context to that quote (emphasis mine):
为该引用添加一些上下文(强调我的):
3.7.1 Simple Command Expansion
3.7.1简单的命令扩展
...
...
If there is a command name left after expansion, execution proceeds as described below .
如果有膨胀后留下了一个命令的名称,执行前进如下所述。 Otherwise , the command exits.
否则 ,该命令退出。 If one of the expansions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed.
如果其中一个扩展包含命令替换,则该命令的退出状态是执行的最后一个命令替换的退出状态。 If there were no command substitutions, the command exits with a status of zero.
如果没有命令替换,则命令以状态为零退出。
3.7.2 Command Search and Execution [ — this is the "below" case ]
3.7.2命令搜索和执行[ - 这是“下面”的情况 ]
IIUC the manual describes var=foo
as special case of var=foo command...
syntax (pretty confusing!). IIUC手册描述了
var=foo
作为var=foo command...
特殊情况var=foo command...
语法(非常令人困惑!)。 The "exit status of the last command substitution" rule only applies to the no-command case. “最后一个命令替换的退出状态”规则仅适用于无命令情况。
While it's tempting to think of export var=foo
as a "modified assignment syntax", it isn't — export
is a builtin command (that just happens to take assignment-like args). 虽然将
export var=foo
视为“修改后的赋值语法”很诱人,但它并不是 - export
是一个内置命令(恰好采用类似赋值的args)。
=> If you want to export a var AND capture command substitution status, do it in 2 stages: =>如果要导出var AND capture命令替换状态,请分2个阶段执行:
A=$(false)
# ... check $?
export A
This way also works in set -e
mode — exits immediately if the command substitution return non-0. 这种方式也适用于
set -e
模式 - 如果命令替换返回非0,则立即退出。
As others have said, the exit code of the command substitution is the exit code of the substituted command, so正如其他人所说,命令替换的退出代码是被替换命令的退出代码,所以
FOO=$(false)
echo $?
---
1
However, unexpectedly, adding export
to the beginning of that produces a different result:然而,出乎意料的是,将
export
添加到它的开头会产生不同的结果:
export FOO=$(false)
echo $?
---
0
This is because, while the substituted command false
fails, the export
command succeeds, and that is the exit code returned by the statement.这是因为,虽然替换命令
false
失败,但export
命令成功,这就是语句返回的退出代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.