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

2024-10-22 08:28:00
admin
原创
274
摘要:问题描述:我对在执行变量赋值和使用命令替换时命令将返回什么错误代码感到困惑: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命令成功,并且这是语句返回的退出代码。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2079  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1459  
  建筑行业正处于数字化转型的关键时期,建筑产品生命周期管理(PLM)系统的实施对于提升项目效率、质量和协同性至关重要。特别是在 2025 年,基于建筑信息模型(BIM)的项目进度优化工具成为众多建筑企业关注的焦点。这些工具不仅能够整合项目全生命周期的数据,还能通过精准的分析和模拟,为项目进度管理提供强大支持。BIM 与建...
plm是什么软件   0  
  PLM系统开发的重要性与现状PLM(产品生命周期管理)系统在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。它贯穿产品从概念设计到退役的整个生命周期,整合了产品数据、流程以及人员等多方面的资源,极大地提高了企业的协同效率和创新能力。通过PLM系统,企业能够实现产品信息的集中管理与共享,不同部门之间可以实时获取...
国产plm软件   0  
  PLM(产品生命周期管理)系统在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和技术的飞速发展,企业对PLM系统的迭代周期优化需求日益迫切。2025年敏捷认证对项目管理提出了新的要求,其中燃尽图作为一种强大的可视化工具,在PLM系统迭代周期优化中有着广泛且重要的应用。深入探讨这些应用,对于提升企业的项...
plm系统主要干什么的   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用