我需要在Bash中将函数作为参数传递。例如,以下代码:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
应该输出:
before
Hello world
after
我知道eval
在这种情况下是不正确的,但这只是一个例子:)
任何的想法?
Answers:
如果您不需要延迟函数名称或其参数的求值之类的东西,则不需要eval
:
function x() { echo "Hello world"; }
function around() { echo before; $1; echo after; }
around x
做你想要的。您甚至可以通过以下方式传递函数及其参数:
function x() { echo "x(): Passed $1 and $2"; }
function around() { echo before; "$@"; echo after; }
around x 1st 2nd
版画
before
x(): Passed 1st and 2nd
after
function
单词,则必须运行顶级方法才能访问这些内部方法。
我认为没有人完全回答这个问题。他没有问是否可以按顺序回显字符串。相反,问题的作者想知道他是否可以模拟函数指针行为。
有几个答案很像我要做的,我想用另一个例子来扩展它。
来自作者:
function x() {
echo "Hello world"
}
function around() {
echo "before"
($1) <------ Only change
echo "after"
}
around x
为了扩展它,我们将使用函数x echo“ Hello world:$ 1”来显示何时真正执行函数。我们将传递一个字符串,该字符串是函数“ x”的名称:
function x() {
echo "Hello world:$1"
}
function around() {
echo "before"
($1 HERE) <------ Only change
echo "after"
}
around x
为了描述这一点,字符串“ x”被传递到函数echo(),该函数回显“ before”,然后调用函数x(通过变量$ 1,第一个传递给around的参数),传递参数“ HERE”,最后在。
另外,这是使用变量作为函数名称的方法。变量实际上包含作为函数名称的字符串,并且($ variable arg1 arg2 ...)调用传递参数的函数。见下文:
function x(){
echo $3 $1 $2 <== just rearrange the order of passed params
}
Z="x" # or just Z=x
($Z 10 20 30)
给出:30 10 20,在这里我们执行了存储在变量Z中并传递了参数10 20和30的名为“ x”的函数。
在上面我们通过为函数分配变量名称来引用函数,以便我们可以使用变量代替实际知道函数名称(这与在c中非常经典的函数指针情况下为概括程序流而可能执行的操作类似, -选择要基于命令行参数进行的函数调用)。
在bash中,这些不是函数指针,而是引用您以后使用的函数名称的变量。
()
不会启动子外壳?
除了字符串,您不能将其他任何东西传递给函数。进程替换可能会伪造它。Bash倾向于保持打开FIFO,直到其扩展完成的命令为止。
这是一个快速的愚蠢的
foldl() {
echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)
# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)
可以导出函数,但这并不像它第一次出现时那样有趣。我发现它主要用于使调试功能可用于脚本或其他运行脚本的程序。
(
id() {
"$@"
}
export -f id
exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi'
)
id
仍然只得到一个碰巧是函数名(从环境中的序列化自动导入)及其args的字符串。
Pumbaa80对另一个答案的评论也不错(eval $(declare -F "$1")
),但它主要用于数组而不是函数,因为它们始终是全局的。如果要在一个函数中运行它,它所要做的就是重新定义它,因此没有效果。它不能用于创建闭包或部分函数或“函数实例”,这取决于当前范围中发生的任何绑定。充其量,它可以用于将函数定义存储在字符串中,并在其他地方重新定义-但是这些函数也只能进行硬编码,除非eval
使用了
基本上Bash不能这样使用。
评估可能是实现此目标的唯一方法。唯一真正的缺点是它的安全性,因为您需要确保不会传入任何恶意,并且只会调用您要调用的函数(以及检查它是否没有讨厌的字符,例如';'在其中)。
因此,如果您是调用代码的人,那么eval可能是唯一的方法。请注意,还有其他形式的eval也可能会涉及子命令($()和``),但它们并不安全且更昂贵。
eval $1
使用if declare -F "$1" >/dev/null; then eval $1; fi
eval $(declare -F "$1")