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

2024-10-22 08:28:00
admin
原创
272
摘要:问题描述:我对在执行变量赋值和使用命令替换时命令将返回什么错误代码感到困惑: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大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2023  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1450  
  引言PLM(产品生命周期管理)合规性管理在汽车行业正扮演着日益关键的角色。随着汽车产业的不断发展,法规要求愈发严格,消费者对产品质量和安全性的期望也持续攀升。汽车企业需要在整个产品生命周期内确保合规,从设计研发阶段到生产制造,再到产品的售后使用与回收处理。这不仅关乎企业能否避免巨额罚款和法律诉讼,更影响着企业的品牌声誉...
plm是什么意思   4  
  引言企业的可持续发展如今已成为全球关注的焦点,这不仅关乎企业自身的长期生存与繁荣,更对整个社会和环境的健康发展有着深远影响。在实现可持续发展目标的征程中,企业面临着诸多复杂的挑战,涵盖了从资源管理、环境保护到社会责任履行等多个维度。而产品生命周期管理(PLM)系统作为一种强大的数字化工具,正逐渐展现出其在助力企业达成可...
plm软件有哪些   4  
  PLM(Product Lifecycle Management)软件在制造业中扮演着至关重要的角色,它贯穿于产品从概念设计到退役处理的整个生命周期,为企业提供了集成化的管理平台,有效提升了企业的创新能力、生产效率和产品质量。以下将详细阐述 PLM 软件在制造业中的五大核心应用场景。产品设计与研发管理在产品设计与研发阶...
国产plm软件排名   4  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用