#!/bin/bash

testFunction () {
read -p "Question" $1
echo $1
}

testFunction foo

My intention is for read to assign the user input to the variable in the argument, and then echo it out, however instead of echoing user input it echos foo.

I realize to get around this I can use Bash indirection like so:

#!/bin/bash

testFunction () {
read -p "Question" $1
echo ${!1}
}

testFunction foo

However, I would prefer to avoid using this method since not all languages have variable indirection (and I will be moving onto a new language soon enough). Is there any other way I can make it look at foo as if it was a variable? Thanks.

link|improve this question

Do you really believe that other languages will support any other forms of indirection that could be used in bash? – Ignacio Vazquez-Abrams Sep 10 '11 at 8:36
Well, if they don't then, how would this problem be solved in another language? – Whef Sep 10 '11 at 8:44
what's the point of all of this? why do you do it? – Karoly Horvath Sep 10 '11 at 8:47
Although I find that slightly irrelevant to my question, I'll humor you by saying that it's a for a yes/no function I've made (since I had several yes/no functions in my program). I want the yes/no function to be able to check if the user input is equal to [Yy] or [Nn] and then act accordingly. – Whef Sep 10 '11 at 8:48
feedback

3 Answers

up vote 3 down vote accepted

In any language that has a eval-like construct it is possible to interpret a string as a variable name. In Bash:

eval echo \$$foo

In Python:

from __future__ import print_function
eval ( "print (" + foo + ")" )

In most languages that lack eval this is not possible.

link|improve this answer
Thank you for the input, as Python is actually the next language I will be learning. – Whef Sep 10 '11 at 9:08
1  
But you wouldn't do it that way in Python regardless; you'd use a dict. – Ignacio Vazquez-Abrams Sep 10 '11 at 9:08
feedback

You do can do this with eval

testFunction () {
    eval 'read -p "Enter Y or N: " '$1
    eval 'echo $'$1
}

testFunction foo

But eval is not a tool to be used lightly. What you're doing is probably crazy. You should be using an approach like this

testFunction () {
    read -p "Enter Y or N: " bar
    case "$bar" in
        [YyNn]) return 0 ;;
    esac
    return 1
}

testFunction && foo=valid

This way you don't have to re-check $foo later, its value is an answer to the question "Was the input valid?"

But maybe you want, later, to actually do something different based on whether the user said y or n, which I suspect is what drives this "Let's dynamically create a variable from a function" nonsense. In that case you can do something like

testFunction () {
    read -p "Enter Yes or No: " bar
    case "$bar" in
        [Yy][Ee][Ss]|[Yy]) printf y ;;
        [Nn][Oo]|[Nn]) printf n ;;
    esac
}

foo=$(testFunction)

This is functionally similar to the eval version, but it assures that you only get known values into foo. Later you can test the value in foo.

if [ -z "$foo" ] ; then
        echo invalid input
elif [ "$foo" = "y" ] ; then
        echo answered yes
elif [ "$foo" = "n" ] ; then
        echo answered no 
fi

And you can keep this code simple, because all possible values are already known.

link|improve this answer
Make more sense to return 0 for yes and 1 for no, maybe loop on invalid input, but that depends a lot on the application - for a reusable function, provide an option. – tripleee Sep 10 '11 at 12:42
@tripleee: Agreed on all points, but I question the value of completeness and correctness for contrived examples which are as speculative as this. Given a clearer request I'd provide a better answer. – Sorpigal Sep 10 '11 at 23:05
feedback

this is what I would do (based on your comment):

testFunction () {
  read -p "yes or no? [YynN] "  bla
  if [ "$bla" = 'Y' -o "$bla" = 'y' ]; then
      return 0
  fi
  return 1
}

if testFunction; then
  echo "it was yes"
fi

or

testFunction () {
  read -p "yes or no? [YynN] "  bla
  if [ "$bla" = 'Y' -o "$bla" = 'y' ]; then
      echo 1
  else
      echo 0
  fi
}

foo=`testFunction`
echo $foo
link|improve this answer
I still need to dynamically define what variable read will store user input in as opposed to having a fixed variable (bla). – Whef Sep 10 '11 at 9:09
1  
you're still trying to do it at the wrong place. if you do want to do it in the function you have to use indirection. – Karoly Horvath Sep 10 '11 at 9:26
1  
Tangentially, the conditional can be made more elegant using case than this if [ construct. – tripleee Sep 10 '11 at 9:48
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.