【问题标题】:Anonymous functions in shell scriptsshell 脚本中的匿名函数
【发布时间】:2011-12-08 08:09:16
【问题描述】:

是否可以创建类似于匿名函数的东西,其值可以分配给数组元素并在以后调用?我似乎找不到在 bash 脚本中执行此操作的方法,但也许有一种解决方法。

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    简短回答:不。

    长答案:Nooooooooooooo。

    完整答案:bash 中的函数不是一等对象,因此 bash 中不可能有匿名函数。

    【讨论】:

    • 作为一种解决方法,我会用名称定义函数并将名称存储在数组中;那么当你想调用函数时,只需eval数组元素。
    • @choroba 也许您应该将其发布为答案。尽管不能像 Ignacio 所描述的那样直接实现,但您的解决方法是个好主意。
    • CVE-2014-6271 link 中的 bash 漏洞是否确认 shell 脚本中可以存在匿名函数?
    • @Lizz:不。它只是利用了一种方法中的缺陷来创建函数。
    • 完整的解释是NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!没门。忘了它。甚至不要考虑它。走开。
    【解决方案2】:

    有可能;我写了一个库来做到这一点,虽然这是一个非常奇怪的项目。源代码位于http://github.com/spencertipping/bash-lambda。使用这个库:

    $ my_array=()
    $ my_array[0]=$(fn x 'echo $((x + 1))')
    $ my_array[1]=$(fn x 'echo $((x + 2))')
    $ ${my_array[0]} 5
    6
    $ ${my_array[1]} 5
    7
    $
    

    诀窍是让fn 函数创建一个包含函数主体的文件,chmod +x 该文件,然后返回其名称。这会导致杂散文件堆积,这就是库还实现异步标记/清除垃圾收集器的原因。

    【讨论】:

    • 有没有办法在执行匿名函数之前等待命令执行完毕?
    • @William Shell 脚本默认是同步的。如果你运行some_command; ${my_array[0]} 5,或者some_command && ${my_array[0]} 5,这两个表达式都只会在运行some_command之后运行"${my_array[0]} 5。
    【解决方案3】:

    常用的技术是有条件地分配函数定义:

    #!/bin/sh 案例 1 美元 a) foo() { echo case a; };; b) foo() { echo case b; };; *) foo() { 回显默认值; } ;; 经社理事会 富

    【讨论】:

      【解决方案4】:

      如果你真的需要数组来存储函数,你可以定义命名函数并只存储它们的名字。然后,您可以将该函数称为${array[n]}。或者,您可以将它们命名为func1 .. funcN,然后直接调用func$n。

      【讨论】:

      • bash 有declare -n reference_name - 不是匿名的,但名称可以抽象,例如:declare -n aref; a() { echo "function a"; }; aref=a 然后$aref 将执行a。
      • @JackWasey:你能详细说明一下吗?我没有恢复输出。
      • 我打错了。试试echo ${!aref},然后${!aref}
      【解决方案5】:

      好吧 bash 已经完成了,所以这是完全可能的 ;)

      但除此之外,它并不值得考虑。

      您可以通过以下方式模拟这种行为:

      echo myval ; ( foocmd "$_" && barcmd "$_" )
      

      但是为什么?!?

      【讨论】:

        【解决方案6】:

        在 PATH 中创建 fn 文件

        #!/bin/sh
        
        printusage () {
                printf "Create anonymous function, for example\n"
                printf "fn 'echo "$1 $2"'"
                exit 1
        }
        
        
        [ "$#" = "1" ] || printusage
        fun=$1
        [ "$fun" = "" ] && printusage
        fun_file="$(mktemp /tmp/fun_XXXXXX)"
        
        echo "#!/bin/sh" > "$fun_file"
        echo "" >> "$fun_file"
        echo "$fun" >> "$fun_file"
        chmod u+x "$fun_file"
        
        echo "$fun_file"
        

        你可以这样做:

        foo=$(fn 'echo $1')
        ${foo} "bar" 
        

        【讨论】:

          猜你喜欢
          • 2017-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多