为什么 local fn=$(...) 会掩盖 $?状态码

为什么 local fn=$(...) 会掩盖 $?状态码

两个函数定义,唯一的区别是第一个将local存储关键字与赋值结合在一起,而第二个将它们分开:

function foo {
    local fn=$(mktemp -p /path/does/not/exist 2>/dev/null)
    echo $?
}

function bar {
    local fn
    fn=$(mktemp -p /path/does/not/exist 2>/dev/null)
    echo $?
}

foo
bar

这先是“0”,然后是“1”。我希望它先回显“1”,然后再回显“1”。看来 的值$?是赋值给 local 的结果,而不是命令替换的结果。

为什么 bash 4.2.46(1)-release 会有这样的行为?

答案1

我认为这种行为已被明确记录,因为这是一个陷阱(特别是在使用-o errexit! 运行 bash 脚本时),但似乎并非如此。我的手册副本说明了以下内容(about ,其行为与在函数内时的global行为相同):local

除非遇到无效选项,尝试使用 '-f foo=bar' 定义函数,尝试为只读变量分配值,尝试在不使用复合赋值语法 [...] 的情况下为数组变量分配值,其中一个名称不是有效的 shell 变量名,尝试关闭只读变量的只读状态,尝试关闭数组变量的数组状态,或者尝试使用 -f 显示不存在的函数,否则返回状态为零。

因此,这似乎local不是其他编程语言中所期望的关键字:当向 提供类似赋值的参数时local,这并不限定初始化;相反,local 内置命令负责使分配发生,并且返回代码是其local 本身,而不是可能在初始化程序中运行的代码,并且该返回代码仅在上面列出的条件列表中为非零。

也许从更字面意义上回答这个问题,正如 Bishop 在评论中提到的那样,bash 维护者 Chet Ramey 曾经被问到他是否会考虑local在分配期间发生反射失败,并回答说,本质上,分配不是 local主要任务

因为那不是 local 及其兄弟姐妹 [...] 所做的。这些内置函数的存在是为了分配和修改变量属性。作为附加功能,它们同时支持赋值,但重要的功能是属性设置。他们不需要知道该值是如何计算的。 [...] 由于该函数正在设置属性或值,因此退出状态应反映该操作是否成功。

值得注意的是,在zshshell 中也可以观察到相同的行为。

解决方案是将这两个操作分开:

local variable
variable=$( somecommand )

exit_status=$?

相关内容