Bash:传递函数作为参数

时间:2011-04-15 04:08:06

标签: bash function callback parameter-passing

我需要在Bash中传递函数作为参数。例如,以下代码:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  eval $1
  echo "after"
}

around x

应输出:

before
Hello world
after

我知道eval在上下文中不正确,但这只是一个例子:)

有什么想法吗?

7 个答案:

答案 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可能也会涉及子命令($()和``),但它们并不安全且价格昂贵。