我需要在Bash中将一个函数作为参数传递。例如,下面的代码:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
应该输出:
before
Hello world
after
我知道在那个上下文中使用eval
并不正确,但这只是一个例子 :) 你有什么想法吗?我需要在Bash中将一个函数作为参数传递。例如,下面的代码:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
应该输出:
before
Hello world
after
我知道在那个上下文中使用eval
并不正确,但这只是一个例子 :) 你有什么想法吗?如果您不需要任何高级操作,比如延迟评估函数名称或其参数,就不需要使用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 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”传递给函数around(),该函数回显“before”,通过变量$1(传递给around的第一个参数)调用函数x,并传递参数“HERE”,最后回显after。function x(){
echo $3 $1 $2 <== just rearrange the order of passed params
}
Z="x" # or just Z=x
($Z 10 20 30)
执行了存储在变量Z中的名为“x”的函数,并传递参数10,20和30。结果为30 10 20。
上述是通过将变量名分配给函数来引用函数,这样我们可以使用变量代替实际知道函数名称(类似于在c中非常经典的函数指针情况下泛化程序流程但预先选择要基于命令行参数进行的函数调用)。
在bash中,这些不是函数指针,而是引用稍后使用的函数名称的变量。
()
把它包起来?这不会启动一个子 shell 吗? - horseyguy不必使用eval
function x() {
echo "Hello world"
}
function around() {
echo "before"
var=$($1)
echo "after $var"
}
around x
除了字符串,您无法向函数传递任何内容。进程替代可以模拟它。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
仍然只能获取一个字符串,该字符串恰好是函数的名称(从环境中自动导入的序列化)及其参数。
Pumbaa80对另一个答案的评论也很好(eval $(declare -F "$1")
),但它主要适用于数组,而不是函数,因为它们总是全局的。如果您在函数内部运行此代码,则仅会重新定义它,因此没有任何效果。它不能用于创建闭包或部分函数或依赖于当前作用域中绑定的任何内容的“函数实例”。最多可以将函数定义存储在字符串中,并在其他位置重新定义-但这些函数也只能硬编码,除非使用eval
。
基本上,Bash无法像这样使用。
function myfunc()
{
local myresult='some value'
echo "$myresult"
}
result=$(myfunc) # or result=`myfunc`
echo $result
这里的结果被输出到标准输出,调用者使用命令替换来捕获变量中的值。然后可以根据需要使用该变量。
你应该有类似以下的内容:
function around()
{
echo 'before';
echo `$1`;
echo 'after';
}
around x
。eval 可能是实现它的唯一方法。唯一真正的缺点是安全方面,因为您需要确保没有恶意内容被传递,并且只会调用您想要调用的函数(同时检查它是否有像 ';' 这样的恶意字符)。
因此,如果您是调用代码的人,则 eval 可能是唯一的方法。请注意,还有其他形式的 eval 也可能有效,涉及子命令 ($() 和 ``),但它们不够安全并且更昂贵。
if declare -F "$1" >/dev/null; then eval $1; fi
轻松检查 eval $1
是否会调用一个函数。 - user123444555621eval $(declare -F "$1")
- user123444555621
function
关键字,则在运行顶层方法之前无法访问这些内部方法。 - jasonleonhard