bash上的嵌套函数

时间:2016-07-08 10:52:30

标签: bash function

我有一个期望接收另一个要执行的功能的功能

  a(){
     function=$1
     echo "common log! $function"
     $function --> run the function
  }

我想要的是将我的函数中的函数参数作为嵌套函数传递

   b(){
       a f(){ echo "nested function b" }
       echo "since I´m doing more things here"
   }

   c(){
       a f(){ echo "nested function c" }
       echo "since I´m doing more things here"
   }

但似乎嵌套函数f不能在bash上完成

有关如何实现这一目标的任何建议吗?

3 个答案:

答案 0 :(得分:3)

您可以使用子shell函数来使用嵌套函数 - 使用括号而不是大括号:

#!/bin/bash

a() {
    echo "hello a"
}

# Note the (
b() (
    echo "hello b"
    a() {
        echo "inner a"
    }

    a
)

a
b
a

给出:

hello a
hello b
inner a
hello a

无法做到做的是将内部函数传递到其他地方,因为内部函数只存在于子shell中。 Bash没有函数的引用,只有全局名称。

如果你想编写类似闭包的东西,那就使用像Python这样的语言。

答案 1 :(得分:2)

只需按名称定义并传递:

b(){
    f(){ echo "nested function"; }
    a f
    echo "since I´m doing more things here"
}

但请注意,nested functions don't seem to be a thing in bash 因此,在运行上述代码后,f将在全局范围内可用 因此上面的代码相当于:

f(){
    echo "nested function"
}
b(){
    a f
    echo "since I´m doing more things here"
}

答案 2 :(得分:1)

正如其他答复者所说,Bash仅支持全局功能。但是,这并不需要阻止您。您要做的就是将您的“内部”函数定义为全局函数,但只要给它起一个名字就不会被其他人使用。这是一种称为“去功能化”的技术。请注意,您必须非常小心,避免执行恶意代码,否则它可能像小提琴一样开始播放您的脚本。

__inner_b_key=0 # one counter per script, or function, or inner function, or whatever
b() {
    local f
    f=__inner_b_f_$((inner_b_key++))
    # Yes, it's evil
    # But, it's powerful
    eval "function ${f}() { echo \"nested function b\"; }"
    a $f
}

您可以使用另一个技巧“提升lambda”来构成它。如果您的内部函数很复杂,则eval所要求的引号会很快使您发疯。 Lambda提升是将内部函数提升为全局函数,将其自由变量转换为参数的过程。由于Bash已经将“本地”功能提升到了全局范围,您将获得非常不错的效果:

__inner_c_key=0
c() {
   local f
   local computed
   computed=$(doSomething)
   # Do something with computed
   __inner_c_f() {
       # local variables are received as the first arguments
       local computed
       computed=$1
       shift
       # the arguments passed to the wrapper appear after the closure arguments
       # Do another thing with computed
   }
   # a closure is created, by storing the values of c's local variables into
   # the global definition of an anonymous function that wraps the real implementation
   # said anonymous wrapper also forwards the arguments it receives after the arguments
   # consumed to pass the closure
   # ${var@Q} is a Bash 4.4 feature that quotes the value $var such that Bash can
   # reinterpret it back to the same value, which is perfect for eval
   f=__inner_c_f_$((inner_c_key++))
   eval "function ${f}() { __inner_c_f ${computed@Q} \"\$@\"; }"
   higherOrder $f
   # a function with a closure was passed to a higher order function! in Bash!
   # even after this call to c ends, the value of computed lives on inside
   # the definition of $f, which is global and acts as the closure
   # too bad we lack garbage collection!
}

这些转换极其机械化,以至于您看起来像是在充当编译器,利用与其他将功能代码转换为命令性代码的编译器相同的技术,将假设的“功能性Bash”转换为普通的Bash。遵循此机械过程时,您可以希望轻松地确保eval是理智的而不是邪恶的。

相关问题