从子shell返回值并输出到局部变量
Posted
技术标签:
【中文标题】从子shell返回值并输出到局部变量【英文标题】:return value from subshell and output to local variables 【发布时间】:2012-10-11 13:32:01 【问题描述】:我发现了我无法解释的奇怪行为。 以下代码可以正常工作:
function prepare-archive
blah-blah-blah...
_SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/")
exit $?
blah-blah-blah...
表示我得到了我期望的价值:
bash -x ./this-script.sh:
++ exit 1
+ _SPEC_FILE='/home/likern/Print/Oleg/print-service/packaging/print-service.spec
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec'
+ exit 1
只要我将local
定义添加到变量:
local _SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/")
我得到以下信息:
bash -x ./this-script.sh:
++ exit 1
+ local '_SPEC_FILE=/home/likern/Print/Oleg/print-service/packaging/print-service.spec
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec'
+ exit 0
$:~/MyScripts$ echo $?
0
问题:为什么?发生了什么?我可以将 subshell 的输出捕获到 local
变量并可靠地检查 subshell 的返回值吗?
P.S.:prepare-archive
在主 shell 脚本中被调用。第一个exit
是来自check-spec-file
函数的exit
,第二个来自prepare-archive
函数——这个函数本身是从主shell 脚本执行的。我通过exit 1
从check-spec-file
返回值,然后将此值传递给exit $?
。因此,我希望它们应该是相同的。
【问题讨论】:
在什么情况下调用prepare-archive
? ++ exit 1
不适合您显示的任何代码。
【参考方案1】:
要捕获子shell的退出状态,在赋值前将变量声明为local,例如下面的脚本
#!/bin/sh
local_test()
local local_var
local_var=$(echo "hello from subshell"; exit 1)
echo "subshell exited with $?"
echo "local_var=$local_var"
echo "before invocation local_var=$local_var in global scope"
local_test
echo "after invocation local_var=$local_var in global scope"
产生以下输出
before invocation local_var= in global scope
subshell exited with 1
local_var=hello from subshell
after invocation local_var= in global scope
【讨论】:
您介意解释一下这里发生了什么吗?您的回答解决了我的问题,但我仍然不明白它是如何以及为什么这样做的。 @IhorKaharlichenko 如果在声明中使用local
分配变量,则子shell 退出状态将被local
内置命令的退出状态“屏蔽”/覆盖。在赋值之前声明一个局部变量也更便于移植(一些 shell 不支持使用local
进行初始化)。【参考方案2】:
来自 bash 手册,Shell Builtin Commands
部分:
local:
[...]The return status is zero unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.
希望这会有所帮助 =)
【讨论】:
这是否意味着变量定义在没有local
的情况下使用时没有返回状态?为什么?你知道一些解决方法吗 - 因为我不想产生多余的全局变量。
我不知道任何不涉及创建全局变量或使用文件的解决方法,抱歉 =(。我会这样做 local TMPFILE=$(mktemp); check-spec-file > $TMPFILE; local error=$?; local _SPEC_FILE=$(cat $TMPFILE); rm $TMPFILE
@Mephi_stofel - 要解决这个问题,您可以拆分声明和初始化,例如首先是:local my_var
,然后是:my_var=$(my_function)
。初始化将安全地引用局部变量,而不会污染全局范围。
谢谢你,@EliranMalka!我今天遇到了同样的问题,这正是我解决的方法。
调试一小时后发现这个问题真是太棒了,然后你才知道如何在 Google/SO 上搜索。 ;)【参考方案3】:
当我使用 bash 子shell 括号对许多 echo 命令进行分组时,我遇到了这个奇怪的问题。 在我的情况下,我只需要将一个值传回调用 shell,所以我只使用了 exit 命令
RET=0
echo RET: $RET
(echo hello
echo there
RET=123
echo RET: $RET
exit $RET)
RET=$?
echo RET: $RET
给出以下输出
RET: 0
hello
there
RET: 123
RET: 123
如果没有退出命令,你会得到这个令人困惑的:
RET: 0
hello
there
RET: 123
RET: 0
【讨论】:
以上是关于从子shell返回值并输出到局部变量的主要内容,如果未能解决你的问题,请参考以下文章