我需要在Bash中传递函数作为参数。例如,以下代码:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
应输出:
before
Hello world
after
我知道eval
在上下文中不正确,但这只是一个例子:)
有什么想法吗?
答案 0 :(得分:104)
如果您不需要延迟评估函数名称或其参数的任何想法,则不需要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
答案 1 :(得分:20)
我认为没有人能回答这个问题。他没有问他是否能按顺序回应弦乐。相反,问题的作者想知道他是否可以模拟函数指针的行为。
有几个答案与我做的非常相似,我希望用另一个例子来扩展它。
来自作者:
function x() {
echo "Hello world"
}
function around() {
echo "before"
($1) <------ Only change
echo "after"
}
around x
为了扩展这个,我们将有函数x echo&#34; Hello world:$ 1&#34;显示函数执行何时真正发生。我们将传递一个字符串,该字符串是函数&#34; x&#34;:
的名称function x() {
echo "Hello world:$1"
}
function around() {
echo "before"
($1 HERE) <------ Only change
echo "after"
}
around x
为了描述这一点,字符串&#34; x&#34;被传递给函数around(),其中echos&#34;在&#34;之前,调用函数x(通过变量$ 1,传递给周围的第一个参数)传递参数&#34; HERE&#34;,最后回声后。
另外,这是将变量用作函数名称的方法。变量实际上包含作为函数名称的字符串,并且($ 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,我们执行了名为&#34; x&#34;的函数。存储在变量Z中并传递参数10 20和30.
上面我们通过为函数赋值变量来引用函数,所以我们可以使用变量来代替实际知道函数名称(这类似于你在c中用于泛化程序的非常经典的函数指针情况中可能做的事情)流,但预先选择您将根据命令行参数进行的函数调用。)
在bash中,这些不是函数指针,而是引用您以后使用的函数名称的变量。
答案 2 :(得分:16)
无需使用eval
function x() {
echo "Hello world"
}
function around() {
echo "before"
var=$($1)
echo "after $var"
}
around x
答案 3 :(得分:5)
您不能将任何内容传递给字符串以外的函数。流程替换可以有点伪造它。 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。
答案 4 :(得分:2)
更好的方法是在函数中使用局部变量。那么问题就是如何将结果传递给调用者。一种机制是使用命令替换:
function myfunc()
{
local myresult='some value'
echo "$myresult"
}
result=$(myfunc) # or result=`myfunc`
echo $result
此处将结果输出到stdout,调用者使用命令替换来捕获变量中的值。然后可以根据需要使用该变量。
答案 5 :(得分:1)
你应该有以下几点:
function around()
{
echo 'before';
echo `$1`;
echo 'after';
}
然后,您可以致电around x
答案 6 :(得分:-1)
eval可能是实现它的唯一方法。唯一真正的缺点是它的安全方面,因为你需要确保没有任何恶意传入,并且只调用你想要调用的函数(同时检查它没有像';'这样的讨厌字符在其中也是如此)。
因此,如果您是调用代码的人,那么eval可能是唯一的方法。请注意,还有其他形式的eval可能也会涉及子命令($()和``),但它们并不安全且价格昂贵。