5

I have a script where the user input needs to be evaluated several times, the solution im working on is to put the evaluation bits into a function, and simply call the function every time i need to evaluate the input. The problem is though that when im trying to update the $1 variable (that referes to the first variable parameter of the function) I get the error message "$VARIABLE command not found".

Here is the code:

function input_handler() {
 if is_integer $1; then
  selid="$1 -1"
  if [[ "$1" -le "0" ]]; then
   echo "Please use a simple positive number!"
  else
   if [[ "$1" -le "${#array[*]}" ]]; then
    eval $1="${array[selid]}"
    echo "Ok, moving on..."
   else
    echo "That number seems too large, try again?"
   fi
  fi
 else
  if [ -e $2/$1 ]; then
   echo "Ok, moving on..."
  else
   echo "That item is not on the list, try again!"
  fi
 fi
}

And this command:

input_handler $doctype $docpath

Gives this output:

5
./test: line 38: 5=sun: command not found

Ok, moving on...

Now this is almost correct, but what im after is doctype=sun, not 5=sun, in other words I need the $1 variable name not its value. Changing the line eval $1="${array[selid]}" to eval doctype="${array[selid]}" fixes this particular instance. But this does not fix my problem as I need to run this function on different variables with different names.

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Dan-Simon Myrland
  • 327
  • 1
  • 5
  • 10

4 Answers4

4

Maybe not fully understand what you want achieve, but check the next example:

weirdfunc () {
    echo " weirdfunc: variable name is: $1"
    echo " weirdfunc: variable value is: ${!1}"
    eval "$1=$(( ${!1} + 1))" #assign
}

myvar="5"
echo "the value of myvar before: $myvar"

weirdfunc myvar #call with the NAME not with the value, so NOT weridfunc $myvar

echo "the value of myvar after: $myvar"

In short - when you want to do anything with the variable NAME in an called function, you should pass the NAME of the variable and NOT his value. So call the function

somefunc NAME

instead of

somefunc $NAME

and use the above constructs to get the name and value inside the function.

clt60
  • 62,119
  • 17
  • 107
  • 194
  • Perhaps I should clearify what I whant to do. The script that I'm working on pipes out a list of file entries and prompt the user for wich file it should pick, if a valid choise it should be stored in the variable $1 variable. Now so far everything works well, but here is the tricky part; To make the script more user friendly I have added numbers in front of each file entry. The ide is that the user can type a corresponding number in stead of the full filename. But for this to work i need the function to transform his choise "like 5" to a valid filename "like sun" and store that in $1 variable – Dan-Simon Myrland Apr 21 '13 at 14:34
  • if you want change the value of a variable passed __by name__ use the above constructs. If you want set the $1 use @kojiro's answer, but honestly don't understand why want to do this, when you can use any helper variable... The best you can do - show one REALLy SHORT example - without any unrelated "if"s and with the main part too - not only the function alone... – clt60 Apr 21 '13 at 15:03
  • You are absolutely right! I solved this by just adding a helper variable helper="${array[selid]}" instead of eval $1="${array[selid]}", and called this outside the function: input_handler $doctype $docpath
    doctype=$helper
    Sorry if was not being clear, im rather new to stackoverflow and Bash scripting in general. Thanks for all your help!
    – Dan-Simon Myrland Apr 21 '13 at 16:44
  • @Dan-SimonMyrland: Use back-ticks ``like `this` please`` around code in comments. – Jonathan Leffler Apr 21 '13 at 16:45
  • @Dan-SimonMyrland if you need modify a variable outside of the function, the answer showing you the how to do it right. – novacik Apr 21 '13 at 17:43
0

You can't update the value of $1 with a traditional assignment, but you can update the positional parameters with the set builtin.

$ f() { echo "$@"; set -- a b c; echo "$@"; echo $2; }
$ f 1 2 3
1 2 3
a b c
b

Just keep in mind this will wipe out all the positional parameters you don't re-set each time, so you'll need to set $2 if you want to keep it around.

Your best bet is probably to assign the values in the positional parameters to names and just use names from then on.

kojiro
  • 74,557
  • 19
  • 143
  • 201
0

If you protect the variable name, Bash will evaluate and assign to $1 instead of try to execute $1=value.

eval "$1"=${array[selid]}
Joao Morais
  • 1,885
  • 13
  • 20
-1

Positional parameters are read-only. So what you want to do is not possible. You should do something like

foo=$1

and then work with $foo instead of $1

user123444555621
  • 148,182
  • 27
  • 114
  • 126