Bash:传递函数作为参数

cd1*_*cd1 76 bash function callback parameter-passing

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

function x() {
  echo "Hello world"
}

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

around x
Run Code Online (Sandbox Code Playgroud)

应输出:

before
Hello world
after
Run Code Online (Sandbox Code Playgroud)

我知道eval在那种情况下不正确,但这只是一个例子:)

任何的想法?

Ide*_*lic 106

如果您不需要延迟评估函数名称或其参数的任何想法,则不需要eval:

function x()      { echo "Hello world";          }
function around() { echo before; $1; echo after; }

around x
Run Code Online (Sandbox Code Playgroud)

做你想要的.您甚至可以通过这种方式传递函数及其参数:

function x()      { echo "x(): Passed $1 and $2";  }
function around() { echo before; "$@"; echo after; }

around x 1st 2nd
Run Code Online (Sandbox Code Playgroud)

版画

before
x(): Passed 1st and 2nd
after
Run Code Online (Sandbox Code Playgroud)

  • 如果我还有另一个y()函数,可以围绕x 1st 2nd y 1st 2nd做吗?它怎么知道x和y是大约的参数,而1st和2nd是x和y的参数? (2认同)

uDu*_*ude 22

我认为没有人能回答这个问题.他没有问他是否能按顺序回应弦乐.相反,问题的作者想知道他是否可以模拟函数指针行为.

有几个答案很像我要做的,我想用另一个例子来扩展它.

来自作者:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  ($1)                   <------ Only change
  echo "after"
}

around x
Run Code Online (Sandbox Code Playgroud)

为了扩展它,我们将使用函数x echo"Hello world:$ 1"来显示函数执行何时真正发生.我们将传递一个字符串,该字符串是函数"x"的名称:

function x() {
  echo "Hello world:$1"
}

function around() {
  echo "before"
  ($1 HERE)                   <------ Only change
  echo "after"
}

around x
Run Code Online (Sandbox Code Playgroud)

为了描述这一点,字符串"x"被传递给around()函数,其中回显"之前",调用函数x(通过变量$ 1,传递给周围的第一个参数)传递参数"HERE",最后回显echos .

另外,这是使用变量作为函数名称的方法.变量实际上包含作为函数名称的字符串,并且($ 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)
Run Code Online (Sandbox Code Playgroud)

给出:30 10 20,其中我们执行了存储在变量Z中的名为"x"的函数,并传递了参数10 20和30.

上面我们通过为函数指定变量名来引用函数,所以我们可以使用变量来代替实际知道函数名(这与你在c中非常经典的函数指针情况中可能做的类似,用于概括程序流但是pre - 根据命令行参数选择您将要进行的函数调用.

在bash中,这些不是函数指针,而是引用您以后使用的函数名称的变量.

  • 为什么将它包装在`()中?不会启动子shell吗? (2认同)

kur*_*umi 16

没有必要使用 eval

function x() {
  echo "Hello world"
}

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

around x
Run Code Online (Sandbox Code Playgroud)


orm*_*aaj 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)
Run Code Online (Sandbox Code Playgroud)

可以导出函数,但这并不像它第一次出现那么有趣.我发现它主要用于使脚本或运行脚本的其他程序可以访问调试功能.

(
    id() {
        "$@"
    }

    export -f id
    exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi'
)
Run Code Online (Sandbox Code Playgroud)

id 仍然只获取一个恰好是函数名称的字符串(从环境中的序列化中自动导入)及其args.

Pumbaa80对另一个答案的评论也很好(eval $(declare -F "$1")),但它主要用于数组,而不是函数,因为它们总是全局的.如果你要在一个函数中运行它,它所做的就是重新定义它,所以没有任何效果.它不能用于创建闭包或部分函数或"函数实例",这取决于当前作用域中发生的任何事件.最好这可用于将函数定义存储在字符串中,并在其他地方重新定义 - 但这些函数也只能进行硬编码,除非当然eval使用

基本上Bash不能像这样使用.