【问题标题】:Invoke function whose name is stored in a variable in bash调用名称存储在 bash 中的变量中的函数
【发布时间】:2016-01-28 00:04:09
【问题描述】:

假设我有:

function x {
    echo "x"
}
call_func="x"

现在,我可以简单地使用eval,如下所示:

eval $call_func

但我想知道是否有其他方法可以调用名称存储在变量中的函数(如果存在):call_func

【问题讨论】:

    标签: bash shell scripting


    【解决方案1】:

    你应该可以直接使用函数调用

    $call_func
    

    对于其他所有内容,请查看该答案:https://stackoverflow.com/a/17529221/3236102 它不是您直接需要的,但它显示了如何调用命令/函数的许多不同方式。

    但让用户执行任意代码是不好的做法,因为它可能非常危险。这样做会更好:

    if [ $userinput == "command" ];then
        command
    fi
    

    这样,用户只能执行您希望他们执行的命令,甚至可以在输入错误时输出错误消息。

    【讨论】:

    • call_func 中的变量将是一个字符串(取自用户输入)。只是把$call_func 回显它的内容,而不执行函数。
    • 这不应该发生。你说,你用的是bash?如果你输入这个:echo $($call_func),会发生什么?另外,也许尝试以不同的方式解决该问题。让用户执行任意代码是危险的!
    • 啊,nvm。因为里面的函数名和echo是一样的。 :|我现在觉得很傻。
    • 别担心!我添加了更多关于如何更好地处理这种情况的信息。
    • 大约有 20 个可接受的函数名称。目前,我正在搜索是否在字符串(包含所有允许的名称)中找到用户输入,然后在 eval 中找到它(或者现在直接调用它)。不过,我希望有一个更干净的解决方法。
    【解决方案2】:

    请注意:

    变量保存数据,函数保存代码。

    bad practice to mix them,不要尝试。


    是的,只需使用 var。如果 var a 是由a=ls 设置的,那么:

    $ $a
    

    将执行ls。第一个 $ 是 shell 的行提示符。

    【讨论】:

    • 是的。该方法有效。我很困惑,因为x 中的echocall_func 的值相同。
    • 如果我还想用参数(也是变量)调用函数怎么办?
    • @MrCalvin eval "$cmd_with_args"
    • 我对@9​​87654322@ 提供的关于“混合函数和变量”的看法是可以动态构造函数/参数调用,但应该像这样将它们分开:$the_command "${args[@]}" (其中args 是一个数组)以避免奇怪的分词问题。
    【解决方案3】:

    文件处理用例:模拟传递匿名函数

    如果您有 100 个五种不同类型的文件,并且您希望使用不同的函数来处理每种类型的文件,则可以创建一个切换函数,该函数包含一个带有嵌入式 case 语句的 for 循环。

    您的目标是提供以下切换功能:

    1. 文件处理函数的名称。 ($1)

    2. 通过调用适当的文件收集函数得到文件名列表。

    因此,您无需编写单独的函数来循环遍历每种文件,而只需使用一个函数即可。

    #!/bin/sh
    
    ##################################################################
    #        Functions that gather specific kinds of filenames       #
    ##################################################################
    
    function getDogFiles
    {
        local -r TARGET_DIR="$1"
        local fileGlobPattern="*.dog"
    
        ls ${TARGET_DIR}${fileGlobPattern}
    }
    
    function getCatFiles
    {
        local -r TARGET_DIR="$1"
        local fileGlobPattern="*.cat"
    
        ls ${TARGET_DIR}${fileGlobPattern}
    }
    
    function getBirdFiles
    {
        local -r TARGET_DIR="$1"
        local fileGlobPattern="*.bird"
    
        ls ${TARGET_DIR}${fileGlobPattern}
    }
    
    function getFishFiles
    {
        local -r TARGET_DIR="$1"
        local fileGlobPattern="*.fish"
    
        ls ${TARGET_DIR}${fileGlobPattern}
    }
    
    function getFrogFiles
    {
        local -r TARGET_DIR="$1"
        local fileGlobPattern="*.frog"
    
        ls ${TARGET_DIR}${fileGlobPattern}
    }
    
    ##################################################################
    #            Functions that process each type of file.           #
    ##################################################################
    
    function processDogFiles
    {
        local -r FILE_NAME="$1"
        cat $FILE_NAME
    }
    
    function processCatFiles
    {
        local -r FILE_NAME="$1"
        cat $FILE_NAME
    }
    
    function processBirdFiles
    {
        local -r FILE_NAME="$1"
        cat $FILE_NAME
    }
    
    function processFishFiles
    {
        local -r FILE_NAME="$1"
        cat $FILE_NAME
    }
    
    function processFrogFiles
    {
        local -r FILE_NAME="$1"
        cat $FILE_NAME
    }
    
    ##################################################################
    #            Functions to process all of the files               #
    ##################################################################
    
    function processItems
    {
        local -r PROCESSING_FUNCTION=$1
        shift 1
        
        for item in "$@"
        do
            $PROCESSING_FUNCTION "$item"
        done
    }
    
    function processAnimalFiles
    {
        local -r TARGET_DIR="$1"
    
        shift 1  # Remove the target directory from the argument list.
    
        local -ar FILE_TYPES=( "$@" )
    
        processingPrefix="process"
        processingSuffix="Files"
    
        gatheringPrefix="get"
        gatheringSuffix="Files"
    
        for fileType in "${FILE_TYPES[@]}"
        do
            case "$fileType" in
                Dog | Cat | Bird | Fish | Frog)
                    fileProcessingFunction="${processingPrefix}${fileType}${processingSuffix}"
                    fileGatheringFunction="${gatheringPrefix}${fileType}${gatheringSuffix}"
                    processItems "$fileProcessingFunction" $($fileGatheringFunction "$TARGET_DIR")   #    The second argument expands to a list of file names. 
                    ;;
                *)
                    echo "Unknown file type: ${fileType} file." >> /var/log/animalFiles.err.log
                    ;;
            esac
        done
    }
    

    ############################################## ##############################

    local -a animalFiles=(Dog Cat Bird Fish Frog Truck)
    processAnimalFiles "/opt/someapp/data/" "${animalFiles[@]}"
    

    【讨论】:

    • 如此清晰的用例和如此努力 - +1。直到现在还没有其他支持。很奇怪。
    • @Binarus 好吧,我是即时完成的。把它清理干净了!现在应该得到选票。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 2018-02-12
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2018-07-15
    相关资源
    最近更新 更多