我有一个期望接收另一个要执行的功能的功能
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上完成
有关如何实现这一目标的任何建议吗?
答案 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
是理智的而不是邪恶的。