1

CODE with details

#!/usr/bin/bash -xv

FUNCTION_DYNAMIC

eval "function APP_$i_$j
{
    `enter code here`
}"

DEFINING_FUNC_TO_CALCULATE_VALUE

APP_VAR_MKT()
{
    for i in `cat ${SERVER}`
    do
        for j in `cat ${ZONE}`
        do
            shopt -s expand_aliases
            alias name="APP_${i}_${j}"
            declare -fp "APP_${i}_${j}"
        done
    done
}

MAIN

SERVER_NAME=/path/servers_file
ZONE=/path/zones_file

DECLARING FUNCTION with variable in it

APP_VAR_MKT
6
  • Could you show an example of "<file_name_having_5_server_names>" and "<file_name_having_6_zone_names>" , and how they relate? Commented Jan 1, 2018 at 21:42
  • Hello Cdarke, Thanks for the update. in a loop, i'm trying to declare and call a function with dynamically values, is it possible to do this in bash eval "function APP_$i_$j{ echo "something }" APP_VAR_ZONE { for i in cat ${FBF_SERVER};do for j in cat ${TLG_MARKET};do FBF_${i}_${j};done;done } SERVER_NAME=/path/file_name_servers; ZONE=/path/file_name_zones; APP_VAR_ZONE Commented Jan 2, 2018 at 5:01
  • eval is to be avoided if possible, there is usually a better way. Why do you need a function with a dynamic name, why can't you just pass parameters? By the way, using cat to read a file in a loop is a very bad technique, not sure what you are trying to do in your code, can you please format it correctly and put it in your question? Commented Jan 2, 2018 at 9:38
  • Hello, I have updated my code details which I'm trying but it's failing because there is no logic how to define the variable function and how to goto that function after every iteration of i and j. Also server file is having names of 5 different servers and zone file is having names of 5 different parameters so the function should be like for 1 server all the 5 zone parameters processed first and then 2nd serevr with all 5 zone parameters and so on. Commented Jan 2, 2018 at 10:29
  • Why are you mixing an alias with a function? Why don't you pass the server name and zone name as parameters? Why are you using cat instead of read? Commented Jan 2, 2018 at 11:53

4 Answers 4

3

You don't; you pass that information as arguments:

app () {
    server_name=$1
    zone=$2
    # ...
}


app "$SERVER_NAME" "$ZONE"
Sign up to request clarification or add additional context in comments.

Comments

2

Disclaimer: Declaring functions dynamically is not the approach you should use. See chepner's answer, that is definitely the preferred way!

However, if you really want to create the name dynamically, here is another way to do it, that is a little less problematic than eval:

#!/usr/bin/env bash 

SERVER_NAME=foo
ZONE=bar

shopt -s expand_aliases
alias name="APP_${SERVER_NAME}_$ZONE"

name() { 
   echo hello
}

declare -fp "APP_${SERVER_NAME}_${ZONE}"

The output of declare shows that APP_foo_bar has been declared:

APP_foo_bar () 
{ 
    echo hello
}

Now, this works to some degree. You have to be very cautious if the input is not under your control. This can be potentially dangerous:

#!/usr/bin/env bash 

SERVER_NAME='foo() { echo hi; }; echo ouch;'
ZONE=bar

shopt -s expand_aliases
alias name="APP_${SERVER_NAME}_$ZONE"

name() { 
   echo hello
}

declare -fp APP_foo
declare -fp _bar

When the right alias is used, this approach can be used to execute arbitrary code. The output of this script is:

ouch
APP_foo () 
{ 
    echo hi
}
_bar () 
{ 
    echo hello
}

Not only were the wrong functions declared, echo ouch got executed! Now imagine if I used rm -rf *. Using eval presents the exact same problem.


Conclusion: Don't do it :)

1 Comment

I had no idea that aliases would do that. Thanks. And there are some situations where this seems necessary, such as dynamically generating new functions to pass to complete -F ....
0

You should not do this, unless you have a good reason for it - functions are reusable encapsulations of code, and their names should not change normally. Also you should not use eval because it is very dangerous. So be warned.

What you can do if you absolutely must is use eval:

#!/bin/bash

eval "function APP_${SERVER_NAME}_${ZONE}
{
    echo 'XXX'
}"

APP_${SERVER_NAME}_${ZONE}

The result:

XXX

1 Comment

I wouldn't even recommend this with a caveat; you'll need to be aware of everything that ordinarily wouldn't need to be quoted inside the body of the function, as it will be subject to expansion as the argument to eval.
0

As others have said, it is not a good idea to generate function (or variable) names dynamically, instead you can use an associative array in a structure sometimes called a despatch table.

The idea is that the keys of the associative array (sometimes called a 'hash', 'hash table', or dictionary) hold the names of functions. When you need a particular function you just call it. Here is a simple example:

# Statically declare each function

func1() {
    echo "This is func1"
}

func2() {
    echo "This is func2"
}

# Declare the array as associative
declare -A lookup

# Setup the association of dynamic name with function
lookup[APP_fred_CBD]='func1'
lookup[APP_jim_ABCD]='func2'

SERVER_NAME='fred'
ZONE='CBD'
${lookup[APP_${SERVER_NAME}_${ZONE}]}

SERVER_NAME='jim'
ZONE='ABCD'
${lookup[APP_${SERVER_NAME}_${ZONE}]}

Gives:

This is func1
This is func2

If you application does not require unique functions, you can use the same function for more than one key, and pass parameters.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.