我正在使用bash脚本,并且想执行一个函数来打印返回值:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
当我执行时fun2
,它不会打印“ 34”。为什么会这样呢?
function a() { echo 34; }
function b() { while read data; do echo $data ; done ;}
a | b
我正在使用bash脚本,并且想执行一个函数来打印返回值:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
当我执行时fun2
,它不会打印“ 34”。为什么会这样呢?
function a() { echo 34; }
function b() { while read data; do echo $data ; done ;}
a | b
Answers:
尽管bash有一条return
语句,但您只能用它指定函数的自身exit
状态(介于0
和之间的值255
,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 || fun2
将只运行fun2
,如果fun1
返回一个0
值。默认返回值是函数中最后执行的语句的退出值。
fun1
,然后将返回值存储在中$?
。尽管我不建议您这样做…
$?
?
||
构造,@ Blauhirn 将退出代码0视为成功,因此为“ true”。非零是错误,因此为假。可以将其fun1 || fun2
视为“如果fun1返回成功或fun2返回成功”的简写,而不是实际返回值本身的运算符。
$(...)
捕获包含在其中的命令发送到stdout的文本。return
不输出到标准输出。$?
包含最后一个命令的结果代码。
fun1 (){
return 34
}
fun2 (){
fun1
local res=$?
echo $res
}
return
用于设置$?
这是exit status
。在上述例子中,fun1
的exit status
将是34
。另外,请注意,$(...)
除了从指定命令中输出stdout之外,还捕获stderr。
Bash中的函数与其他语言中的函数不同;它们实际上是命令。因此,函数的使用就好像它们是从您的路径中获取的二进制文件或脚本一样。从程序逻辑的角度来看,应该没有任何区别。
Shell命令通过管道(也称为流)连接,而不是像“真实”编程语言那样通过基本或用户定义的数据类型连接。没有像命令的返回值这样的东西,可能主要是因为没有真正的方法来声明它。它可能出现在手册页或--help
命令的输出中,但两者都是人类可读的,因此会随风而逝。
当命令想要获取输入时,它将从其输入流或参数列表中读取该命令。在这两种情况下,都必须解析文本字符串。
当命令想要返回某些内容时,它必须将echo
其返回到其输出流。另一种常用的方法是将返回值存储在专用的全局变量中。写入输出流更清晰,更灵活,因为它还可以接收二进制数据。例如,您可以轻松返回BLOB:
encrypt() {
gpg -c -o- $1 # encrypt data in filename to stdout (asks for a passphrase)
}
encrypt public.dat > private.dat # write function result to file
就像其他人在该线程中编写的一样,调用者也可以使用命令替换$()
来捕获输出。
并行地,该函数将“返回” gpg
(GnuPG)的退出代码。将退出代码视为其他语言所没有的奖励,或者视您的性格而定,将其作为shell函数的“ Schmutzeffekt”。按照惯例,此状态为0表示成功,否则为1-255范围内的整数。为了明确起见:(return
如exit
)只能接受0-255之间的值,而0以外的值不一定是错误的,正如经常断言的那样。
当您不提供显式值时return
,状态取自Bash语句/函数/命令中的最后一条命令,依此类推。因此,总有一种状态,return
这只是提供状态的一种简便方法。
其他答案的问题是它们要么使用全局(全局),而当调用链中有多个函数时,可以覆盖全局;或者echo
这意味着您的函数无法输出诊断信息(您将忘记函数执行此操作以及“结果”,即返回值,将包含比呼叫者期望的更多的信息,从而导致奇怪的错误),或者eval
过于繁琐。
这样做的正确方法是将顶层内容放入函数中,并使用local
带有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
,可以通过管道传递/ out,他们可以返回退出代码。基本上,在脚本中定义命令和创建可以从命令行调用的可执行文件之间没有区别。
因此,不要像这样编写脚本:
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
为as local
,所有其他函数均通过返回值ret_val
。
另请参见以下Unix和Linux问题: Shell函数中的局部变量的范围。
ya.teck发表的一个使用,这可能是根据情况的另一种甚至更好的解决方案local -n
。
如果在定义函数的脚本中运行,我喜欢执行以下操作:
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使用多个数组返回值
现金代码:
#!/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:
return
在您的情况下,基本上与的exit code
范围相同0 - 255
。echo
按照@septi的建议使用。退出代码可以使用捕获$?
。