保留返回值并且不从子shell

时间:2018-05-19 17:00:27

标签: linux bash environment-variables scoping subshell

我正在调用一些将VARIABLE设置为某个值并返回另一个值的函数。我需要保留VARIABLE的值,并将函数的返回值分配给另一个VAR。这是我试过的:

bar() {
        VAR="$(foo)"
        echo $VARIABLE >&2
        echo $VAR >&2
}

foo() {
        VARIABLE="test"
        echo "retval"
}
bar

但它打印

retval

有办法吗?

3 个答案:

答案 0 :(得分:3)

ksh有一个方便的非子shelling命令替换构造:

#!/bin/ksh
foo() {
  echo "cat"
  variable="dog"
}
output="${ foo }"
echo "Output is $output and the variable is $variable"

bash和其他shell中,您必须通过临时文件来代替:

#!/bin/bash

foo() {
  echo "cat"
  variable="dog"
}

# Create a temp file and register it for autodeletion
file="$(mktemp)"
trap 'rm "$file"' EXIT

# Redirect to it and read it back
foo > "$file"
output="$(< "$file")

echo "Output is $output and the variable is $variable"

答案 1 :(得分:3)

BASH不像传统函数式编程语言那样向调用者返回值。 BASH函数唯一可以返回的(本质上)是函数的“退出代码”。

要启用函数以向另一个函数提供结果,您应该使用全局变量。默认情况下,除非另有说明,否则所有变量都是全局变量。

这是一组带有一些echo语句的函数,可以帮助你理解这一点:

#!/bin/bash

export VARIABLE=""

bar() {
        echo ">>> In function bar() ... "
        echo "        _var :: $_var"
        echo "    VARIABLE :: $VARIABLE"

        echo ">>> Setting '_var' to value 'local to bar' ... "
        local _var="local to bar"

        echo ">>> calling function foo() ... "
        foo
        echo ">>> Back in function bar() ... "

        echo "        _var :: $_var"
        echo "    VARIABLE :: $VARIABLE"
}

foo() {
        echo ">>> In function foo() ... "

        local _var="local to foo"
        VARIABLE="I'm a global variable"

        echo "        _var :: $_var"
        echo "    VARIABLE :: $VARIABLE"
}
bar

在上面的例子中,我们将“_var”变量设置为范围内的本地变量。当“bar()”出现时,我们将本地“_var”的值设置为“local to bar”。我们随后调用函数“foo()”;它将局部变量“_var”设置为“local to foo”。

我们还将全局变量“VARIABLE”设置为“我是全局变量”的值。

当执行返回“bar()”函数时,我们打印VARIABLE和_var。 VARIABLE导致字符串“我是一个全局变量”。

有关BASH中函数的返回值的详细信息,请参阅问题Return value in a Bash function

以上是上述结果:

>>> In function bar() ...
        _var ::
    VARIABLE ::
>>> Setting '_var' to value 'local to bar' ...
>>> calling function foo() ...
>>> In function foo() ...
        _var :: local to foo
    VARIABLE :: I'm a global variable
>>> Back in function bar() ...
        _var :: local to bar
    VARIABLE :: I'm a global variable

请注意,我们从未在“bar()”函数中设置VARIABLE的值。它在“foo()”中设置,随后,我们使用全局变量访问结果。

局部变量“_var”也说明这些值只是每个函数的“本地”,并且通过指定它们是本地的,它们在函数本身之外没有任何值或含义。

您可以使用子shell来执行您想要的操作。但是,子壳在单独的处理空间中运行,因此您经常会遇到意想不到的副作用。要在子shell示例中使用:

#!/bin/bash

export VARIABLE="default global value"

function bar()
{
    VAR=$(foo)
    echo "VARIABLE :: $VARIABLE"
    echo "     VAR :: $VAR"
}

function foo()
{
    # in theory, VARIABLE is globally scoped, but called in a
    # subshell, it won't impact/change the calling environment
    export VARIABLE='test'
    echo "$VARIABLE"
}

bar

尽管以这种方式通过子shell捕获输出仍然有效 - 如果您的函数返回或输出多个值,您最终可能会遇到您不想要的奇怪行为。上面的例子说明了对函数的随意观察表明“foo()”会改变全局范围内“VARIABLE”的值。但是因为它是在子shell('$(foo)')中运行的 - 它实际上根本不会改变全局VARIABLE值。

这可能会导致较大的脚本中存在细微的逻辑错误,我建议不要使用此方法。以下是上述代码段的输出:

VARIABLE :: default global vaule
     VAR :: test

答案 2 :(得分:3)

嗯,这可能很难看,但是 -

在bash中,除非声明local,否则所有变量都是全局变量。因此,您可以直接在VAR中分配foo

bar() {
        #### VAR="$(foo)"
        foo                  # Just call it
        echo $VARIABLE >&2
        echo $VAR >&2
}

foo() {
        VARIABLE="test"
        #### echo "retval"
        VAR="retval"         # What would have gone in $VAR before
}
bar

输出:

test
retval