函数的返回值

函数的返回值

my_var=$(my_func arg1 arg2 ..)有人可以解释一下,当我查看代码示例时,为什么 bash 函数的返回值总是在函数中回显,然后由 消耗。

my_func ()
   {
   echo "$1 , $2, $3"
   }

my_var=$(my_func .. .. ..);

而不是使用这个,它不会打开子shell

declare g_RV  #-- global return value for all functions

myfunc ()
   {
   g_RV="$1 , $2, $3"
   }

myfunc .. .. ..; my_var=$g_RV;

因为我使用第二种方法,并且想知道在某些情况下这是否会对第一种方法失败。肯定是有原因的,因为大家都在打开一个subshel​​l。

编辑:由于 Kusalananda 和 Paul_Pedant 评论,
我添加了一个带有 g_RV - LAF function 的递归函数调用,列出目录 $1 的所有文件,或者如果 $2 INT>0 则递归
,然后在函数内部调用其他函数(查看求和函数!

declare g_RV

shopt -s dotglob nullglob

#-- Recursive call with g_RV
#---------------------------
#-- call: LAF [directory STR] [recursive INT (>0 .. true, 0 .. false)]  ... List all files in a folder or inclusive all files in subfolders (recursive
LAF ()
   {
   local file files="" dir_path=$1
   if [[ ${dir_path:0:1} != "/" ]]; then dir_path=$(readlink -f "$dir_path"); fi
   
   for file in "$dir_path/"*; do
      if [[ -d $file ]]; then (($2)) && { LAF "$file"; files+=$g_RV; }                    #-- recursive call
      else files+="${file}"$'\n'; fi
      done
   g_RV=$files
   }
   
LAF "/tmp" 1; my_var1=$g_RV; echo "$my_var1";

#-- function calling other functions with g_RV
#---------------------------------------------
sum_A ()
   { 
   g_RV=$(($1+$2))
   }

sum_B()
   {
   g_RV=$(($1+$2))
   }

sum_C ()
   {
   local -i sum=0;
   sum_A 5 6; sum+=$g_RV
   sum_B 12 18; sum+=$g_RV
   g_RV=$sum
   }
  
sum_C; my_var2=$g_RV; echo "sum: $my_var2";

答案1

标准工具和实用程序通过以下方式返回信息标准输出,用退出状态限定结果(0=正常,否则错误)。您的函数应该执行相同的操作,以便可以以相同一致的方式使用它们。

您的示例显示了所有函数返回的单个全局变量。一旦采用这种方法,您就无法在管道甚至字符串中插入函数,而不增加复杂性并降低可读性。

考虑

f() { sed 's/^/> /'; }
g() { nl; }

echo try | f | g    # "     1  > try"

如果每个函数的返回都有一个全局变量(或者更糟糕的是,两个函数都有相同的全局变量),那么您将需要跳过重重困难才能达到相同的效果。

您正在运行一个 shell,当您考虑所有开销时,子进程的数量在很大程度上是无关紧要的。如果您需要速度,请不要编写 shell 脚本。

答案2

使用全局变量通常是不可重用的。可能会与其他地方使用的全局变量发生名称冲突。

而且,这并不是大多数人期望函数工作的标准方式。

答案3

  • 更少的代码
  • 更容易阅读
  • 传统方式不太可能导致错误
  • echo是一个内置函数,计算成本几乎为零
  • Bash 是一个 Bourne Again SHell,它是不是一种[经典]编程语言
  • 经典的做事方式是有弹性的source/.——这意味着无论如何它总是有效的。

答案4

它不是总是就这样做了。事实上,你只是在你的问题中以另一种方式做到了!

Shell 函数实际上不能返回除退出状态以外的任何内容,退出状态仅限于 0..255 之间的整数,因此不是很有用。然后,选项是使用外部变量,或者打印所需的数据并捕获输出。

打印和捕获输出也不是没有问题;即使我们忽略大多数 shell 因命令替换而遇到的性能问题,也存在输出是单个字符串或字节流、没有任何结构的问题。在 zsh 以外的 shell 中,命令替换无论如何都无法捕获 NUL 字节,因此它甚至不是 8 位干净的字节流。

如果您需要返回一个数组,那么使用外部变量可能会简单得多。您可以使用 namerefs 来允许调用者传递用于返回值的变量名称,而不是使用具有固定名称的变量。

例如,作为一个愚蠢的例子,只是为了拥有一些在没有适当数组的情况下难以处理的值:

#!/bin/bash
funnystrings() {
    declare -n _dst="$1"
    _dst[0]="foo bar"
    _dst[1]="*"
    _dst[2]=$'new\nline'
}

a=()
funnystrings a
declare -p a

同样,如果需要在输入变量中传递另一个变量名称:

squares() {
    declare -n _src="$1" _dst="$2"
    local _i _val
    for _i in "${!_src[@]}"; do
        _val=${src[$i]}
        _dst[$i]=$(( _val * _val ))
    done
}
a=(1 2 3)
b=()
squares a b

这实际上可能在 Bash 中起作用,即使absquares a b请注意,嵌套局部变量在 shell 之间的工作方式可能存在奇怪之处,尤其是。对于什么搭配unset

相关内容