繁体   English   中英

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

[英]Exit code of variable assignment to command substitution in Bash

当简单地执行变量赋值和命令替换时,我对命令将返回什么错误代码感到困惑:

a=$(false); echo $?

它输出1 ,这让我认为变量赋值不会清除最后一个错误代码或产生新的错误代码。 但是当我尝试这个时:

false; a=""; echo $?

它输出0 ,显然这是a=""返回的内容,它覆盖了false返回的1

我想知道为什么会这样,变量赋值有什么特殊性不同于其他普通命令吗? 或者只是因为a=$(false)被认为是单个命令并且只有命令替换部分才有意义?

- 更新 -

谢谢大家,从答案和评论中我明白了“当您使用命令替换分配变量时,退出状态就是命令的状态。” (by @Barmar),这个解释非常清楚易懂,但是speak对程序员来说不够精确,我想看看TLDP或GNU手册页等权威人士对这一点的参考,请帮助我找到它出来了,再次感谢!

在执行命令时, $(command)允许$(command)输出替换自身

当你说:

a=$(false)             # false fails; the output of false is stored in the variable a

命令false产生的输出存储在变量a 此外,退出代码与命令生成的相同。 help false会告诉:

false: false
    Return an unsuccessful result.

    Exit Status:
    Always fails.

另一方面,说:

$ false                # Exit code: 1
$ a=""                 # Exit code: 0
$ echo $?              # Prints 0

导致该工作分配的退出代码到a要返回其为0


编辑:

引自手册

如果其中一个扩展包含命令替换,则该命令的退出状态是执行的最后一个命令替换的退出状态。

引自BASHFAQ / 002

如何在变量中存储命令的返回值和/或输出?

...

output=$(command)

status=$?

output的赋值对command的退出状态没有影响,退出状态仍在$?

请注意,在函数中使用local时不是这种情况。 这是与接受的答案中描述的微妙不同的行为,以及此处发布的链接: http//mywiki.wooledge.org/BashFAQ/002

以这个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

这是这个的输出:

nick.parry@nparry-laptop1:~$ ./tmp.sh 
output: Doing some stuff.
exitCode: 0
output: Doing some stuff.
exitCode: 1

也许没有人关心,但我做到了。 我花了一分钟时间弄清楚为什么我的状态代码总是为0时显然不是。 不是100%明白为什么。 但只知道这有帮助。

我昨天(2018年8月29日)遇到了同样的问题。

除了local提到的Nick P.的答案和@ sevko在接受的答案中的评论, declare在全球范围内也有相同的行为。

这是我的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"

输出:

$ ./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

请注意上面输出中的local_ret2global_ret2的值。 退出代码被localdeclare覆盖。

我的Bash版本:

$ echo $BASH_VERSION 
4.4.19(1)-release

(不是原始问题的答案,但评论太长)

注意export A=$(false); echo $? export A=$(false); echo $? 输出0! 显然, devnull答案中引用的规则不再适用。 为该引用添加一些上下文(强调我的):

3.7.1简单的命令扩展

...

如果有膨胀后留下了一个命令的名称,执行前进如下所述。 否则 ,该命令退出。 如果其中一个扩展包含命令替换,则该命令的退出状态是执行的最后一个命令替换的退出状态。 如果没有命令替换,则命令以状态为零退出。

3.7.2命令搜索和执行[ - 这是“下面”的情况 ]

IIUC手册描述了var=foo作为var=foo command...特殊情况var=foo command...语法(非常令人困惑!)。 “最后一个命令替换的退出状态”规则仅适用于无命令情况。

虽然将export var=foo视为“修改后的赋值语法”很诱人,但它并不是 - export是一个内置命令(恰好采用类似赋值的args)。

=>如果要导出var AND capture命令替换状态,请分2个阶段执行:

A=$(false)
# ... check $?
export A

这种方式也适用于set -e模式 - 如果命令替换返回非0,则立即退出。

正如其他人所说,命令替换的退出代码是被替换命令的退出代码,所以

FOO=$(false)
echo $?
---
1

然而,出乎意料的是,将export添加到它的开头会产生不同的结果:

export FOO=$(false)
echo $?
---
0

这是因为,虽然替换命令false失败,但export命令成功,这就是语句返回的退出代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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