2

Is there a way in bash to understand the name of a variable that's passed to it?

Example:

var1=file1.txt
err_var=errorfile.txt

function func1 {
   echo "func1: name of the variable is: " $1
   echo "func1: value of variable is: " $1 
   echo
   if [ ! -e $var1 ]
   then
      $1 = $err_val  #is this even possible?
   fi
   func2 $1
}

function func2 {
   echo "func2: name of the variable is: " $1
   echo "func2: value of variable is: " $1 
   echo
}

func1 $var1
func1 $err_var

I was hoping to get the following output if file1.txt exists:

func1: name of the variable is: var1
func1: value of variable is: file1.txt

func2: name of the variable is: var1
func2: value of variable is: file1.txt

And when file1.txt does not exist:

func1: name of the variable is: var1
func1: value of variable is: file1.txt

func2: name of the variable is: err_var
func2: value of variable is: errorfile.txt

Any ideas?

jared
  • 1,344
  • 4
  • 20
  • 38

2 Answers2

11

No, the variable is expanded before the function sees it. The function only sees the value, not the variable name.

If you pass the variable name unexpanded and without the dollar sign, you can use indirection.

get_it () {
    echo "${!1}"
}

Demo:

$ foo=bar
$ baz=qux
$ get_it foo
bar
$ get_it baz
qux
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • Thanks Dennis. Is it possible to set the variable in the function without statically defining the variable? i.e. call get_it foo and have the function set foo = somethingelse by doing something like get_it () { $1=foosomething echo "${!1}" } – jared Jun 08 '12 at 21:52
  • @jared: You could use `declare`, but that automatically makes the variable local. You can use `export`, but that obviously exports the variable to any child processes (which *may* be undesirable). `set_it () { export "$1"="something_else"; }; bar=one_thing; set_it bar; get_it bar` – Dennis Williamson Jun 08 '12 at 22:23
  • You can also use `eval`. See https://stackoverflow.com/questions/9714902/how-to-use-a-variables-value-as-other-variables-name-in-bash – Fabio Jan 05 '18 at 03:48
0

Like Dennis said, once you've expanded the variable using the dollar-sign, your function no longer has a way to get the variable name. But I think you also asked about a way to set the variable's value, and that part hasn't been answered yet. There are some non-portable ways to do that, like with declare -n (Google that if you're interested), but my answer is going to stick to a universal solution.

I'm a C++ programmer, so I like to mimic the "getter and setter" philosophy, where you use tiny little functions to get and set the value of a variable. The downside to using getters and setters is that you need to create a function (or two functions) for every value you want to manage. So... I made a "factory function" that handles creating getters/setters for you:

makeGetSet() {
. /dev/fd/0 <<END_FUNC
${1}Val()  { [ "\${1}" ] && ${1}="\${1}" || echo "\${${1}}"; }
END_FUNC
}

It does not require any particular shell with special features like indirection or namerefs, or the declare utility. No eval, no aliases, just 100% POSIX. You just pass in your variable name to makeGetSet, and your getter/setter function has that same name with a "Val" at the end (e.g. myVariableVal). Tested with bash and dash. You're free to continue using the "normal" shell ways to read/write to your variable in combination with my function.

Usage:

Setup: makeGetSet myVariable
Set: myVariableVal newValue
Get: anotherVariable="`myVariableVal`"
Print: myVariableVal

I wasn't sure about a couple parts of your script, so I took some educated guesses. Where you have if [ ! -e $var1 ], I think you meant if [ ! -e $1 ]. And at the end, where you call the functions, you had func1 $var1 and func1 $err_var, but I think you meant to just use func1 $var1 or have a third variable. It looks like $err_var is a "default value for errors" rather than something you'd give as input, but maybe I'm not following your idea.

So my answer to your question would look like:

var1=file1.txt; makeGetSet var1
err_var=errorfile.txt; makeGetSet err_var

function func1 {
   echo "func1: name of the variable is: " ${1%Val}
   echo "func1: value of variable is: " `${1}`
   echo
   # Shorter than if..fi
   [ ! -e `${1}` ] && ${1} ${err_val}
   func2 ${1}
}

function func2 {
   echo "func2: name of the variable is: " ${1%Val}
   echo "func2: value of variable is: " `${1}` 
   echo
}

func1 ${var1}
Sean
  • 393
  • 2
  • 11