min*_*dia 267 bash function return-value
我正在使用bash脚本,我想执行一个函数来打印返回值:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Run Code Online (Sandbox Code Playgroud)
当我执行时fun2,它不会打印"34".为什么会这样?
tam*_*gal 340
虽然bash有一个return语句,但你唯一能用它指定的是函数自身的exit状态(0和之间的值255,0表示"成功").所以return不是你想要的.
您可能希望将return语句转换为echo语句 - 这样可以使用$()大括号捕获函数输出,这似乎正是您想要的.
这是一个例子:
function fun1(){
echo 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Run Code Online (Sandbox Code Playgroud)
另一种获取返回值的方法(如果你只想返回0-255的整数)是$?.
function fun1(){
return 34
}
function fun2(){
fun1
local res=$?
echo $res
}
Run Code Online (Sandbox Code Playgroud)
另外,请注意,您可以使用返回值来使用布尔逻辑,fun1 || fun2只有fun2在fun1返回0值时才会运行.默认返回值是函数中执行的最后一个语句的退出值.
Ign*_*ams 65
$(...)捕获由其中包含的命令发送到stdout的文本.return不输出到stdout.$?包含最后一个命令的结果代码.
fun1 (){
return 34
}
fun2 (){
fun1
local res=$?
echo $res
}
Run Code Online (Sandbox Code Playgroud)
And*_*ler 53
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
Run Code Online (Sandbox Code Playgroud)
正如其他人在此线程中编写的那样,调用者也可以使用命令替换$()来捕获输出.
同时,该函数将"返回" gpg(GnuPG)的退出代码.将退出代码视为其他语言没有的奖励,或者根据您的性情,将其视为shell函数的"Schmutzeffekt".按照惯例,此状态在成功时为0,或者在其他情况下为1-255范围内的整数.为了清楚起见:return(like exit)只能取0到025之间的值,而0之外的值不一定是错误,通常是断言.
当您没有提供显式值时return,状态取自Bash语句/函数/命令中的最后一个命令,等等.所以始终存在状态,并且return只是提供它的简单方法.
Aus*_*ips 26
该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
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*ndt 11
作为其他人优秀帖子的补充,这里有一篇总结这些技术的文章:
Oli*_*ver 10
其他答案的问题是它们要么使用全局(全局),而在调用链中有多个函数时可以覆盖全局,或者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
Run Code Online (Sandbox Code Playgroud)
这个输出
nothing
hi
bye
Run Code Online (Sandbox Code Playgroud)
动态作用域意味着ret_val根据调用者指向不同的对象!这不同于词法作用域,这是大多数编程语言所使用的。这实际上是一个已记录的功能,很容易遗漏,并且没有很好地解释,这里是该功能的文档(强调是我的):
函数本地变量可以使用本地内置声明。这些变量仅对函数及其调用的命令可见。
对于具有C / C ++ / Python / Java / C#/ javascript背景的人来说,这可能是最大的障碍:bash中的函数不是函数,它们是命令,并且具有如下行为:它们可以输出到stdout/ stderr,可以通过管道传递/ out,他们可以返回退出代码。基本上,在脚本中定义命令与创建可以从命令行调用的可执行文件之间没有区别。
因此,不要像这样编写脚本:
top-level code
bunch of functions
more top-level code
Run Code Online (Sandbox Code Playgroud)
这样写:
# define your main, containing all top-level code
main()
bunch of functions
# call main
main
Run Code Online (Sandbox Code Playgroud)
where main()声明ret_val为as local,所有其他函数均通过返回值ret_val。
另请参见以下Unix&Linux问题:Shell函数中的局部变量的范围。
ya.teck所发布的是一种根据情况根据情况甚至可能更好的解决方案local -n。
ya.*_*eck 10
实现此目的的另一种方法是名称引用(需要Bash 4.3+)。
function example {
local -n VAR=$1
VAR=foo
}
example RESULT
echo $RESULT
Run Code Online (Sandbox Code Playgroud)
echo我能想到的最简单的方法是在方法体中使用,如下所示
get_greeting() {
echo "Hello there, $1!"
}
STRING_VAR=$(get_greeting "General Kenobi")
echo $STRING_VAR
# Outputs: Hello there, General Kenobi!
Run Code Online (Sandbox Code Playgroud)
如果在定义函数的脚本中运行,我喜欢执行以下操作:
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"
Run Code Online (Sandbox Code Playgroud)
我喜欢这个,因为如果我愿意,我可以在我的函数中包含echo语句
my_function() {
echo "-> my_function()"
# do stuff
POINTER="my_function_return"
echo "<- my_function. $POINTER"
}
Run Code Online (Sandbox Code Playgroud)