Invoke function whose name is stored in a variable in bash

Please, Take note of:

Variables hold data, functions hold code.

It is bad practice to mix them, do not try to do it.


Yes, just use a var. If the var a was set by a=ls, then:

$ $a

will execute ls. The first $ is the line prompt of the shell.


File Processing Use Case: Emulate Passing Anonymous Functions

If you have 100 files of five different types, and you want a different function to process each type of file, you can create a switching function that contains a for loop with an embedded case statement.

Your goal would be to supply the switching function with:

  1. The name of the file processing function. ($1)

  2. A list of filenames by calling the appropriate file gathering function.

Hence, instead of writing separate functions to loop through each kind of file, you just use one function to do that.

#!/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[@]}"

You should be able to just call the function directly using

$call_func

For everything else check out that answer: https://stackoverflow.com/a/17529221/3236102 It's not directly what you need, but it shows a lot of different ways of how to call commands / functions.

Letting the user execute any arbitrary code is bad practice though, since it can be quite dangerous. What would be better is to do it like this:

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

This way, the user can only execute the commands that you want them to and can even output an error message if the input was incorrect.