简体   繁体   English

Bash中变量赋值命令替换的退出代码

[英]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 on command '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_ret2global_ret2的值。 The exit codes are overwritten by local and declare . 退出代码被localdeclare覆盖。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM