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

Reo*_*orx 48 linux bash shell exit-code

我很困惑这个命令在明确地执行变量赋值时会返回什么错误代码并且使用命令替换:

a=$(false); echo $?
Run Code Online (Sandbox Code Playgroud)

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

false; a=""; echo $?
Run Code Online (Sandbox Code Playgroud)

它输出0,显然这是a=""返回和它覆盖1返回的false.

我想知道为什么会发生这种情况,变量赋值中是否存在与其他正常命令不同的特殊性?或者只是因为a=$(false)被认为是一个命令,只有命令替换部分才有意义?

- 更新 -

谢谢大家,从答案和评论中我得到了"当您使用命令替换分配变量时,退出状态是命令的状态." (由@Barmar提供),这个解释非常清晰易懂,但对于程序员来说说话不够精确,我想从TLDP或GNU手册页等权威人士那里看到这一点的参考,请帮我找到它出来,再次感谢!

dev*_*ull 59

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

当你说:

a=$(false)             # false fails; the output of false is stored in the variable a
Run Code Online (Sandbox Code Playgroud)

命令生成的输出false存储在变量中a.此外,退出代码与命令生成的相同. help false会说:

false: false
    Return an unsuccessful result.

    Exit Status:
    Always fails.
Run Code Online (Sandbox Code Playgroud)

另一方面,说:

$ false                # Exit code: 1
$ a=""                 # Exit code: 0
$ echo $?              # Prints 0
Run Code Online (Sandbox Code Playgroud)

导致a返回赋值的退出代码,即0.


编辑:

引自手册:

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

引自BASHFAQ/002:

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

...

output=$(command)

status=$?

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

  • 请记住,这不适用于`local`变量(例如,`local output = $(command)`),因为`local`是一个命令本身,它的退出代码将覆盖指定函数的那个​​. (47认同)
  • 关于@sevko和@qodeninja关于`local`s的评论,除非变量也是`readonly`,否则这很容易被声明后的初始化所规避:`local my_var; my_var = $(命令); 本地状态= $?` (19认同)
  • 我的天,这浪费了我太多的时间。谢谢@sevko,我自己可能从来没有想过这个。 (5认同)
  • [Bash Pitfall #27](https://mywiki.wooledge.org/BashPitfalls#local_var.3D.24.28cmd.29) 中描述了将“local”声明与命令替换相结合的陷阱。它还会影响“声明”和“导出”。 (3认同)

Nic*_* P. 11

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

以这个bash脚本为例:

#!/bin/bash

function funWithLocalAndAssignmentTogether() {
    local output="$(echo "Doing some stuff.";exit 1)"
    local exitCode=$?
    echo "output: $output"
    echo "exitCode: $exitCode"
}

function funWithLocalAndAssignmentSeparate() {
    local output
    output="$(echo "Doing some stuff.";exit 1)"
    local exitCode=$?
    echo "output: $output"
    echo "exitCode: $exitCode"
}

funWithLocalAndAssignmentTogether
funWithLocalAndAssignmentSeparate
Run Code Online (Sandbox Code Playgroud)

这是这个的输出:

nick.parry@nparry-laptop1:~$ ./tmp.sh 
output: Doing some stuff.
exitCode: 0
output: Doing some stuff.
exitCode: 1
Run Code Online (Sandbox Code Playgroud)

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

  • 原因是`local`(同样适用于`export`)是一个bash内置函数,在第一个示例中调用它的方式导致成功,因此退出代码为'0'。 (2认同)

Zhi*_*Zhu 5

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

除了Nick P. 的回答和 @sevko 在接受的答案local中的评论中提到的之外,在全球范围内也有相同的行为。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"
Run Code Online (Sandbox Code Playgroud)

输出:

$ ./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
Run Code Online (Sandbox Code Playgroud)

请注意上面输出中的local_ret2和的值。global_ret2退出代码被local和覆盖declare

我的 Bash 版本:

$ echo $BASH_VERSION 
4.4.19(1)-release
Run Code Online (Sandbox Code Playgroud)