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:
The name of the file processing function. ($1)
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.