在Bash函数中返回值

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

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

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

626181 次浏览

尽管Bash有return语句,但你唯一可以用它指定的是函数自己的exit状态(值在0255之间,0表示“成功”)。所以return不是你想要的。

你可能想要将你的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返回一个非- __abc3值,fun1 || fun2将只运行fun2。默认返回值是函数中执行的最后一条语句的退出值。

$(...)捕获内包含的命令发送到标准输出的文本。return不输出到标准输出。$?包含最后一个命令的结果代码。

fun1 (){
return 34
}


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

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
}

Bash中的函数不同于其他语言中的函数;它们实际上是命令。因此,函数就像从路径中获取的二进制文件或脚本一样使用。从程序逻辑的角度来看,实际上不应该有任何区别。

Shell命令是通过管道(又名流)连接的,而不是基本的或用户定义的数据类型,如"real"编程语言。没有命令的返回值这样的东西,可能主要是因为没有真正的方法来声明它。它可以出现在手册页上,也可以出现在命令的--help输出中,但两者都是人类可读的,因此被写入到风中。

当一个命令想要获取输入时,它会从输入流或参数列表中读取它。在这两种情况下都必须解析文本字符串。

当一个命令想要返回一些东西时,它必须echo它到它的输出流。另一种常用的方法是将返回值存储在专用的全局变量中。写入输出流更加清晰和灵活,因为它也可以接受二进制数据。例如,你可以很容易地返回:

encrypt() {
gpg -c -o- $1 # Encrypt data in filename to standard output (asks for a passphrase)
}


encrypt public.dat > private.dat # Write the function result to a file

正如其他人在这个线程中所写的那样,调用者还可以使用命令替换$()来捕获输出。

同时,函数将&;return&;gpg (GnuPG)的退出代码。把退出码看作是其他语言没有的额外奖励,或者,根据你的性情,把它看作一个“schmutzeffekt”。shell函数的。按照惯例,这个状态在成功时为0,在其他情况下为1-255范围内的整数。要明确一点:return(像exit一样)只能接受0-255之间的值,而不是0的值不一定是错误,就像通常所断言的那样。

当你没有使用return提供显式值时,状态将从Bash语句/函数/命令中的最后一条命令中获取。所以状态总是存在的,而return只是提供状态的一种简单方法。

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

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"
}

Windows上的Git Bash多个返回值使用数组

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:

作为对其他人优秀文章的补充,这里有一篇文章总结了这些技巧:

  • 设置一个全局变量
  • 设置一个全局变量,将其名称传递给函数
  • 设置返回代码(并使用$?)
  • 'echo'一些数据(并使用MYVAR=$(myfunction)获取它)

Bash函数返回值 . bb0 . rref ="https://www.linuxjournal.com/content/return-values-bash-functions" rel="noreferrer">

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

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

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指向不同的对象,这取决于调用者!这与大多数编程语言使用的词法作用域不同。这实际上是文档化的特性,只是很容易忽略,并且没有很好地解释。以下是它的文档(重点是我的):

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

.

对于具有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声明为local,所有其他函数通过ret_val返回值。

另见Unix &Linux < / >问题 Shell函数中局部变量的作用域

另一个可能更好的解决方案是由ya.teck发布,它使用local -n

另一种实现方法是名称的引用(需要Bash 4.3+)。

function example {
local -n VAR=$1
VAR=foo
}


example RESULT
echo $RESULT

你可以创建一个函数,用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?

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

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

我能想到的最简单的方法是在方法体中像这样使用echo

get_greeting() {
echo "Hello there, $1!"
}


STRING_VAR=$(get_greeting "General Kenobi")
echo $STRING_VAR
# Outputs: Hello there, General Kenobi!