我有一个函数,期望接收另一个要执行的函数
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上完成
关于如何实现这一点的任何建议?
您可以使用子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这样的语言。
只需定义并按名称传递:
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"
}
正如其他回答者所说,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 lifting”来构建它。如果你的内在功能有任何复杂性,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
s是理智而不是邪恶的。