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

2024-10-22 08:28:00
admin
原创
255
摘要:问题描述:我对在执行变量赋值和使用命令替换时命令将返回什么错误代码感到困惑:a=$(false); echo $? 它输出1,这让我认为变量赋值不会清除或在最后一个变量赋值时产生新的错误代码。但是当我尝试这样做时:false; a=""; echo $? 它输出0,显然这就...

问题描述:

我对在执行变量赋值和使用命令替换时命令将返回什么错误代码感到困惑:

a=$(false); echo $?

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

false; a=""; echo $?

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

我想知道为什么会发生这种情况,变量赋值有什么特殊性吗?与其他普通命令不同吗?或者只是因为它a=$(false)被视为单个命令,只有命令替换部分有意义?

- 更新 -

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


解决方案 1:

执行命令时,$(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

导致返回分配的退出代码,a0


编辑:

引用手册中的话:

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

引用自BASHFAQ/002:

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

...

output=$(command)

status=$?

分配给 对的退出状态output没有影响command,该状态仍然在 中$?

这不是 bash 特有的。引用 The Open Group Base Specifications Issue 7, POSIX.1-2017 中“Shell & Utilities”卷 2.9.1 节“简单命令”的结尾:

如果没有命令名称,但命令包含命令替换,则命令将以最后执行的命令替换的退出状态完成

解决方案 2:

请注意,与 结合使用时情况并非如此local,如。即使失败,该表单也会成功退出。local variable="$(command)"`command`

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

输出如下:

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

这是因为local实际上是一个内置命令,而像 这样的命令替换 的输出后会调用。因此您可以从 获得退出状态。local variable="$(command)"`local command`local

解决方案 3:

我昨天(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"

输出:

$ ./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_ret2请注意上面输出中的和 的值global_ret2。退出代码被local和覆盖declare

我的 Bash 版本:

$ echo $BASH_VERSION 
4.4.19(1)-release

解决方案 4:

(这不是对原始问题的回答,但太长了,无法评论)

请注意输出 0!显然, devnull 的答案export A=$(false); echo $?中引用的规则不再适用。为该引文添加一些背景信息(重点是我的):

3.7.1 简单命令扩展

...

如果扩展后还有命令名,则执行按如下所述进行。否则,命令退出。如果其中一个扩展包含命令替换,则命令的退出状态是执行的最后一个命令替换的退出状态。如果没有命令替换,则命令以零状态退出。

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

IIUC 手册将其描述var=foo语法特例var=foo command...(相当令人困惑,从语义上讲它们非常不同!)。“最后一个命令替换的退出状态”规则仅适用于无命令的情况。

尽管很容易将其视为export var=foo“修改后的赋值语法”,但它并不是——它export是一个内置命令(只是恰好采用了类似赋值的参数)。

=> 如果您想要导出 var 并捕获命令替换状态,请分两个阶段进行:

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

这种方式在set -e模式下也有效——如果命令替换返回非 0 则立即退出。

解决方案 5:

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

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

然而,出乎意料的是,export在开头添加却产生了不同的结果:

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

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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1335  
  信创产业的蓬勃发展推动着各行业数字化转型加速,数据库迁移作为其中关键一环,面临诸多挑战。信创数据库迁移旨在将传统数据库平稳过渡到信创环境,以满足自主可控、安全可靠的需求。这一过程涉及技术、业务等多方面因素,稍有不慎就可能出现各种问题,影响业务的正常运行。深入探讨信创数据库迁移过程中的常见问题及解决方案,对于保障迁移工作...
2027年信创国产化   0  
  随着信息技术的飞速发展,信创国产化成为了国家战略的重要组成部分。国产化信创产品名录涵盖了众多领域,其在各个关键应用场景中发挥着重要作用。而信创国产化操作系统作为其中的核心环节,具备五大核心优势,为我国信息技术产业的自主可控发展提供了坚实支撑。关键应用场景之办公领域在办公领域,国产化信创产品有着广泛且深入的应用。如今,越...
国产信创系统   0  
  随着信息技术的飞速发展,信创国产化操作系统在政府部门的推广应用具有重要的战略意义。它不仅关乎国家信息安全,更是推动国内信息技术产业自主创新、实现科技自立自强的关键举措。在当前复杂的国际形势下,政府部门积极推广信创国产化操作系统,对于保障国家政务信息的安全稳定运行,提升信息技术的自主可控能力,具有不可替代的重要作用。推广...
信创产品有哪些   0  
  在企业数字化转型的进程中,信创数据库解决方案的选择至关重要。它不仅关乎企业数据的安全存储与管理,更影响着企业业务的稳定运行与未来发展。合适的信创数据库能够助力企业在复杂多变的市场环境中提升竞争力,保障数据主权与安全。然而,面对市场上众多的信创数据库产品和解决方案,企业往往感到困惑,不知如何做出正确的选择。接下来,我们将...
信创电脑   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用