1

I would like to test if the name of a variable given as argument to a function contains a certain string, and do different actions if it does/does not.

Here is a very basic description of what I want to achieve:

#!/bin/bash

 varA="a"
 varB="b"
 varC="c"
 varD="d"
 varE="e"
 varF="f"

 function1 ()
 {
         if name of argument $1 does not contain "A"; then
                echo "no A in $1"
                further actions done using the value of varA and others...
         elif name of argument $1 contains "A"; then
                echo "A in $1"
                further actions done using the value of varA and others...
         fi
 }

 function1 $varA $varB $varC
 function1 $varD $varE $varF     

And when running this would give

A in varA
no A in varD

I saw while doing some research that the name of a variable could be referred to as ${!var@}, so here is the code I tried:

  1 #!/bin/bash
  2 
  3 varA="a"
  4 varB="b"
  5 varC="c"
  6 varD="d"
  7 varE="e"
  8 varF="f"
  9 
 10 function1 ()
 11 {
 12         if [[ "${!1@}" != *"A" ]]; then
 13                 echo "no A in $1"
 14         elif [[ "${!1@}" == *"A" ]]; then
 15                 echo "A in $1"
 16         fi
 17 }
 18 
 19 function1 $varA $varB $varC
 20 function1 $varD $varE $varF

But when running the script it gives the following error messages:

./testx.sh: line 12: ${!1@}: bad substitution
./testx.sh: line 12: ${!1@}: bad substitution

Any help would be much appreciated! Thank you

6
  • 1
    I don't think it's possible with positional arguments. When the function is called the variables are replaced with values already so there is no variable name to refer to. Commented Aug 24, 2016 at 15:54
  • The call is actually function1 $varA $varB $varC (see my second code), and I am not using the values of the variables here, but in the real script I am working on, I want to use their values to perform other actions in the function. Commented Aug 24, 2016 at 16:44
  • @arielle: OK. In that case, It's not possible. Note that ${!prefix@} "Expands to the names of variables whose names begin with prefix"; that is, it is the equivalent to the file glob prefix*, but over the names of shell variables. prefix is just a string of characters. Commented Aug 24, 2016 at 16:48
  • I see. Then why can't I use ${!@}? Shouldn't this expand to the names of all arguments, something like varA varB varC or $varA $varB $varC? Both would be good for what I want to do. When I try it it gives some empty lines as output. Commented Aug 24, 2016 at 16:52
  • 2
    @arielle: {!@} is not valid, but if it were valid it would be the list of all variables. An argument is just a string; arguments don't have names. (More precisely, they do have names: $1, $2, ...., but those are parameter names, not variable names. The expression which produced the argument is not its name.) The reason you can't do what you want to do is that the argument has already undergone parameter expansion by the time your function sees it, so it is just a string (which is the value of the variable). Commented Aug 24, 2016 at 16:56

3 Answers 3

3

If you want to "test if the name of a variable" then give that to the function:

function1 varA

Not the contents of the variable:

function1 $varA             # INCORRECT

Then, you could test the name of the variable inside the function:

if [[ $1 == *A* ]]; then

The script could be as this one:

#!/bin/bash

function1 ()
{
        if [[ $1 == *A* ]]; then
               echo "A in $1"
        else
               echo "no A in $1"
        fi
}

function1 varA varB varC
function1 varD varE varF

IF you need "the value of the var" inside the function, then just use this:

value=${!1}

That is called "indirect expansion" inside the man bash.

After that, value will contain a copy of the variable named in $1.

To change the value of the variable pointed by $1, use this:

declare $1=newvalue

Or, quite insecure if the value of $1 could be set by an external user:

eval $1=newvalue

The use of ${!var*} (or ${!var@}) is to get a list of all variables that use a name that start with var. Not to reference a particular variable.

$ eval var{A..F}=1               # create the list of variables
$ echo ${!var*}                  # use the expansion to list variables
varA varB varC varD varE varF

The expansion of ${!1*} should have been the list of variables that start with a 1. Those variable names are invalid (except as positional parameters) in bash. That is: variable names could not start with a number.

That expansion is (therefore) an error, and reported as so by bash.

Sign up to request clarification or add additional context in comments.

1 Comment

That makes a lot of sense! Thank you for taking the time to explain this :)
1

You should have been doing

function1 "${!var*}"

and inside the function

if [[ "$1" == *"A"* ]]
then
  echo "At least one variable name  has patttern A"
fi

4 Comments

but in my real script I want to use the value of the first argument to do more actions inside the function, not just its name, would it still work?
Might not be possible with positional arguments @arielle. :(
I did not know "${!var*}" syntax to find all the defined variables starting with var. Thanks!
@anishsane : in fact I came to know about it a couple of months ago when skimming through [ this ] page. This was adopted from ksh IIRC and it first appeared in bash version 2.04 .
0

Be aware the script you are looking for checks only for the first variable of the function call (i.e. $1). So calling for function1 $varA $varB $varC would only check for varA

The code below would do the work you expect under the pseudo code you have written:

#!/bin/bash

varA="checkAinvariable"
varB="b"
varC="c"
varD="d"
varE="e"
varF="f"

function1 ()
{
        if [[ "$1" != *"A"* ]]; then
                echo "no A in $1"
        elif [[ "$1" == *"A"* ]]; then
                echo "A in $1"
        fi
}

function1 $varA $varB $varC
function1 $varD $varE $varF

Output would be:

A in checkAinvariable
no A in d

1 Comment

The op said name of a variable given as argument to a function contains a certain string. It's name not the value pal !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.