我很担心命令在执行变量赋值时会返回什么错误代码,并且命令替换:
a=$(false); echo $?
它输出1
,这让我认为变量赋值不会扫描或产生最后一个错误代码。但是当我尝试这个时:
false; a=""; echo $?
它会输出0
,显然这是a=""
返回的内容,它会覆盖1
返回的false
。
我想知道为什么会发生这种情况,变量赋值中是否有任何与其他正常命令不同的特殊性?或者只是因为a=$(false)
被认为是单个命令而只有命令替换部分才有意义?
- 更新 -
感谢大家,从答案和评论中我得到了“当您使用命令替换分配变量时,退出状态是命令的状态。” (由@Barmar提供),这个解释非常清晰易懂,但对于程序员来说说话不够精确,我想从TLDP或GNU手册页等权威人士那里看到这一点的参考,请帮我找到它出来,再次感谢!
答案 0 :(得分:54)
执行$(command)
命令时,允许output of the command to replace itself。
当你说:
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
。
编辑:
引用manual:
如果其中一个扩展包含命令替换,则退出 命令的状态是最后一个命令的退出状态 替换。
引自BASHFAQ/002:
如何在a中存储命令的返回值和/或输出 可变吗
...
output=$(command)
status=$?
output
的作业对command
的退出状态没有影响 仍在$?
。
答案 1 :(得分:9)
请注意,在函数中使用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%明白为什么。但只是知道这有帮助。
答案 2 :(得分:1)
昨天(2018年8月29日)我遇到了同样的问题。
除了Nick P.'s answer中提到的local
和accepted answer中@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_ret2
和global_ret2
的值。退出代码被local
和declare
覆盖。
我的Bash版本:
$ echo $BASH_VERSION
4.4.19(1)-release
答案 3 :(得分:0)
(不是原始问题的答案,但评论时间太长)
请注意export A=$(false); echo $?
输出0!显然,devnull's answer中引用的规则不再适用。为该引用添加一些上下文(强调我的):
3.7.1简单命令扩展
...
如果扩展后还有一个命令名称,则执行按中的所述进行。 否则,该命令退出。如果其中一个扩展包含命令替换,则该命令的退出状态是执行的最后一个命令替换的退出状态。如果没有命令替换,则命令退出状态为零。
3.7.2命令搜索和执行[ - 这是“下面”案例]
IIUC手册将var=foo
描述为var=foo command...
语法的特例(非常令人困惑!)。 “最后一个命令替换的退出状态”规则仅适用于无命令情况。
虽然将export var=foo
视为“已修改的赋值语法”很诱人,但它不是 - export
是内置命令(恰好采用类似赋值的args)。
=>如果要导出var AND capture命令替换状态,请分两个阶段执行:
A=$(false)
# ... check $?
export A
这种方式也适用于set -e
模式 - 如果命令替换返回非0,则立即退出。