我正在使用一个bash脚本,我想执行一个函数打印返回值:

function fun1(){
  return 34
}
function fun2(){
  local res=$(fun1)
  echo $res
}

当我执行fun2时,它不会打印“34”。为什么会这样呢?


当前回答

return语句设置函数的退出代码,与exit对整个脚本的作用大致相同。

最后一个命令的退出码总是在$?变量。

function fun1(){
  return 34
}

function fun2(){
  local res=$(fun1)
  echo $? # <-- Always echos 0 since the 'local' command passes.

  res=$(fun1)
  echo $?  #<-- Outputs 34
}

其他回答

如果在定义函数的脚本中运行,我喜欢做以下事情:

POINTER= # Used for function return values

my_function() {
    # Do stuff
    POINTER="my_function_return"
}

my_other_function() {
    # Do stuff
    POINTER="my_other_function_return"
}

my_function
RESULT="$POINTER"

my_other_function
RESULT="$POINTER"

我喜欢这样,因为我可以在函数中包含echo语句

my_function() {
    echo "-> my_function()"
    # Do stuff
    POINTER="my_function_return"
    echo "<- my_function. $POINTER"
}

尽管Bash有一个返回语句,但你唯一可以用它指定的是函数自己的退出状态(0到255之间的值,0表示“成功”)。所以返回不是你想要的。

您可能希望将return语句转换为echo语句——这样就可以使用$()花括号捕获函数输出,这似乎正是您想要的。

这里有一个例子:

function fun1(){
  echo 34
}

function fun2(){
  local res=$(fun1)
  echo $res
}

获取返回值的另一种方法(如果您只想返回一个0-255的整数)是$?

function fun1(){
  return 34
}

function fun2(){
  fun1
  local res=$?
  echo $res
}

另外,请注意,您可以使用返回值来使用布尔逻辑-如fun1 || fun2将只在fun1返回非0值时运行fun2。默认返回值是函数中执行的最后一条语句的退出值。

其他答案的问题是,它们要么使用全局变量,当几个函数在一个调用链中时,它可以被覆盖,要么使用echo,这意味着你的函数不能输出诊断信息(你会忘记你的函数是这样做的,而“结果”,即返回值,将包含比调用者期望的更多的信息,导致奇怪的错误),要么使用eval,这太沉重了。

正确的方法是将顶级的东西放在一个函数中,并使用带有Bash动态作用域规则的局部函数。例子:

func1()
{
    ret_val=hi
}

func2()
{
    ret_val=bye
}

func3()
{
    local ret_val=nothing
    echo $ret_val
    func1
    echo $ret_val
    func2
    echo $ret_val
}

func3

这个输出

nothing
hi
bye

动态作用域意味着ret_val指向不同的对象,这取决于调用者!这与大多数编程语言使用的词法作用域不同。这实际上是一个有文档记录的特性,只是很容易被忽略,也没有很好地解释。以下是它的文档(重点是我的):

函数的局部变量可以用局部变量声明 内装式。这些变量仅对函数和对象可见 它调用的命令。

对于具有C、c++、Python、Java、c#或JavaScript背景的人来说,这可能是最大的障碍:bash中的函数不是函数,它们是命令,并且它们的行为是这样的:它们可以输出到stdout/stderr,它们可以通过管道输入/输出,并且它们可以返回退出代码。基本上,在脚本中定义命令和创建可从命令行调用的可执行文件之间没有任何区别。

所以不要像这样写脚本:

Top-level code
Bunch of functions
More top-level code

这样写:

# Define your main, containing all top-level code
main()
Bunch of functions
# Call main
main

main()将ret_val声明为本地,所有其他函数通过ret_val返回值。

请参见Unix和Linux问题Shell函数中局部变量的作用域。

另一个,根据情况可能更好的解决方案,是由你发布的。使用本地-n的Teck。

你可以创建一个函数,用eval修改输入参数,而不是用整个函数输出调用var=$(func)。

var1="is there"
var2="anybody"

function modify_args() {
    echo "Modifying first argument"
    eval $1="out"
    
    echo "Modifying second argument"
    eval $2="there?"
}

modify_args var1 var2
# Prints "Modifying first argument" and "Modifying second argument"
# Sets var1 = out
# Sets var2 = there?

这可能是有用的情况下,你需要:

打印到函数范围内的stdout/stderr(不返回) 返回(set)多个变量。

Git Bash在Windows上使用数组表示多个返回值

Bash代码:

#!/bin/bash

## A 6-element array used for returning
## values from functions:
declare -a RET_ARR
RET_ARR[0]="A"
RET_ARR[1]="B"
RET_ARR[2]="C"
RET_ARR[3]="D"
RET_ARR[4]="E"
RET_ARR[5]="F"


function FN_MULTIPLE_RETURN_VALUES(){

   ## Give the positional arguments/inputs
   ## $1 and $2 some sensible names:
   local out_dex_1="$1" ## Output index
   local out_dex_2="$2" ## Output index

   ## Echo for debugging:
   echo "Running: FN_MULTIPLE_RETURN_VALUES"

   ## Here: Calculate output values:
   local op_var_1="Hello"
   local op_var_2="World"

   ## Set the return values:
   RET_ARR[ $out_dex_1 ]=$op_var_1
   RET_ARR[ $out_dex_2 ]=$op_var_2
}


echo "FN_MULTIPLE_RETURN_VALUES EXAMPLES:"
echo "-------------------------------------------"
fn="FN_MULTIPLE_RETURN_VALUES"
out_dex_a=0
out_dex_b=1
eval $fn $out_dex_a $out_dex_b  ## <-- Call function
a=${RET_ARR[0]} && echo "RET_ARR[0]: $a "
b=${RET_ARR[1]} && echo "RET_ARR[1]: $b "
echo
## ---------------------------------------------- ##
c="2"
d="3"
FN_MULTIPLE_RETURN_VALUES $c $d ## <--Call function
c_res=${RET_ARR[2]} && echo "RET_ARR[2]: $c_res "
d_res=${RET_ARR[3]} && echo "RET_ARR[3]: $d_res "
echo
## ---------------------------------------------- ##
FN_MULTIPLE_RETURN_VALUES 4 5  ## <--- Call function
e=${RET_ARR[4]} && echo "RET_ARR[4]: $e "
f=${RET_ARR[5]} && echo "RET_ARR[5]: $f "
echo
##----------------------------------------------##


read -p "Press Enter To Exit:"

预期的输出:

FN_MULTIPLE_RETURN_VALUES EXAMPLES:
-------------------------------------------
Running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[0]: Hello
RET_ARR[1]: World

Running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[2]: Hello
RET_ARR[3]: World

Running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[4]: Hello
RET_ARR[5]: World

Press Enter To Exit: