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

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


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

评论

您的情况下的return本质上与退出代码相同,范围在0-255之间。使用@septi建议的echo。退出代码可以用$?捕获。

在这种情况下,在fun1中已经使用echo会更加灵活。这是unix编程的想法:echo将结果发送到标准输出,然后可以由res = $(fun1)的其他函数重用-或者直接通过管道传递给其他函数:function a(){echo 34; }函数b(){读取数据时;做echo $ data;完成;} b

这样做的正确方法是将顶级内容放入函数中,并使用具有bash动态范围规则的局部变量。我将创建一个答案来进行演示,它不是一项众所周知的功能,而是一个完全受支持的功能。

另请参阅:stackoverflow.com/a/8743103/12887

参见linuxjournal.com/content/return-values-bash-functions

#1 楼

尽管bash具有return语句,但是您只能用它自己指定的状态是函数自己的exit状态(介于0255之间的值,0表示“成功”)。所以return并不是您想要的。
您可能希望将return语句转换为echo语句-这样,您可以使用$()大括号捕获函数输出,这似乎正是您想要的。这是一个示例:
function fun1(){
  echo 34
}

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

另一种获取返回值的方法(如果只想返回一个0-255的整数)是$?。您可以使用返回值来使用布尔逻辑,例如fun1 || fun2仅在fun2返回非fun1值时才运行0。默认返回值是函数中执行的最后一条语句的退出值。

评论


您需要执行fun1,然后将返回值存储在$?中。尽管我不建议您这样做…

–塔马斯加尔
13年6月27日在7:25

为什么不使用$ ??

– Pithikos
14年8月29日在17:48

不,我需要该死的返回值。到地狱回声。

–TomášZato-恢复莫妮卡
15年4月21日在19:29

@Blauhirn在这种环境下,||构造时,退出代码0被视为成功,因此为“ true”。非零是错误,因此为假。想想fun1 || fun2是“如果fun1返回成功或fun2返回成功”的简写,而不是实际返回值本身的运算符。

– davidA
16 Mar 30 '16 at 21:08

令人讨厌的是,应该提供数据的函数也不能将其他内容回显到stdout,因为使用$()的调用者也将收到该信息,并感到困惑或不得不解析输出。全局变量并不是很好,因为在两个可能嵌套的地方使用相同的全局变量只是时间问题,并且数据可能会丢失。应该有单独的通道来打印数据和发送数据。

–奥利弗
18年8月2日在22:19

#2 楼

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

fun1 (){
  return 34
}

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


评论


是的,返回值用于设置$?这是退出状态。在上面的示例中,fun1的退出状态为34。此外,请注意,除了指定命令中的stdout外,$(...)还捕获stderr。

–swoop81
17年11月27日在21:33



#3 楼

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

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

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

当命令想要返回某些内容时,必须将其返回到其输出流。另一种常用的方法是将返回值存储在专用的全局变量中。写入输出流更清晰,更灵活,因为它还可以接收二进制数据。例如,您可以轻松地返回一个BLOB: />
并行地,该函数将“返回” echo(GnuPG)的退出代码。将退出代码视为其他语言所没有的奖励,或者根据您的性格将其视为外壳函数的“ Schmutzeffekt”。按照惯例,此状态为0表示成功,否则为1-255范围内的整数。为了明确起见:$()(例如gpg)只能接受0-255之间的值,而0以外的值不一定是错误的,就像经常断言的那样。当您不使用return提供显式值时,状态取自Bash语句/函数/命令中的最后一个命令,依此类推。因此始终存在状态,而exit只是提供状态的一种简便方法。

评论


+1,用于解释功能与命令以及这如何影响将数据发送回调用方的概念

–奥利弗
18年8月2日在22:16

+1用于解释shell编程是关于通过管道连接命令的信息。其他编程语言通过返回类型组成函数。 Bash通过文本流编写命令。

– jrahhali
18年2月2日,0:10

如果某个功能必须同时执行该怎么办?也就是说,从脚本发送一些输出,并生成一些文本作为其返回值,而该函数必须将其记录到脚本的stdout中,而这不会受到干扰。

– SasQ
9月5日下午5:01

tldp.org/LDP/abs/html/complexfunct.html Bash:函数返回一个值,称为退出状态。这类似于命令返回的退出状态。退出状态可以由return语句显式指定,否则为函数中最后一条命令的退出状态(如果成功,则为0,否则为非零错误代码)。可以通过将其引用为$?在脚本中使用此退出状态。这种机制有效地允许脚本函数具有类似于C函数的“返回值”。

– opinion_no9
12月11日15:38



#4 楼

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
}


评论


res的价值是什么?

–艾伦
6月29日21:51

#5 楼

其他答案的问题是它们要么使用一个全局函数(在调用链中有多个函数时就可以覆盖它),要么使用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指向不同的对象,具体取决于呼叫者,召集者!这与大多数编程语言所使用的词法作用域不同。这实际上是一个已记录的功能,很容易遗漏,并且没有很好解释,这里是它的文档(强调是我的):内置有本地
。这些变量仅对函数及其调用的命令可见。对于具有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的解决方案,具体取决于情况,甚至可能更好。

评论


根据我的阅读,local与POSIX不兼容,几乎每个shell都以不同的方式实现它,因此它不是可移植的解决方案。

–user2465201
12月4日17:00

#6 楼

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

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

example RESULT
echo $RESULT


评论


任何人都想知道-n = 的作用是什么:使新创建的变量成为对指向的另一个变量的引用。对的进一步分配是在引用的变量上执行的。

–Valerio
19/12/3在14:18

#7 楼

作为其他人的精彩文章的补充,这是一篇总结这些技术的文章:
设置返回码(并用$取?)
'echo'一些数据(并用MYVAR = $(myfunction)取)

从中返回值重击功能

评论


这是最好的答案,因为本文彻底讨论了所有选项。

–mzimmermann
3月3日,17:57

#8 楼

如果在定义了该函数的脚本中运行,我喜欢执行以下操作:想要

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"


#9 楼

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