LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash Scripts - need help with variables (https://www.linuxquestions.org/questions/linux-newbie-8/bash-scripts-need-help-with-variables-867144/)

greengrocer 03-08-2011 02:46 AM

Bash Scripts - need help with variables
 
Hello all,

I want to create a script that processes parameters which a user might specify when they call my script.

example of how I want my script to be able to be used:

Code:

sh myscript red green orange
I'd imagine I want to be able to do something like:

Code:

p=1
 for ARG in "$@"
  do
  I want to make a variable(p) contain whatever the first parameter is
  let p=p+1
  and then variable(p) contain whatever the second parameter is
  and so on until there are no more parameters. 
done

In usage, the user calling my script could specify any quantity of parameters.

I am just not sure how to go about getting variables like this to work. Can anybody point me in the correct direction?

Cheers,
Greenie

colucix 03-08-2011 03:08 AM

If I understand well you want to assign the positional parameters to the array elements. If this is the case you can simply do
Code:

array=("$@")
Then you can check the array length and refer to the array elements using the proper syntax.

greengrocer 03-08-2011 03:32 AM

Thanks, I just did a quick read on Arrays and that method might be easiest if I can just get the basics working.

The following:
Code:

#!/bin/bash

array=("$@")

Yields

Quote:

myscript.sh 3: Syntax error: "(" unexpected
Then I tried something simple:
Code:

#!/bin/bash

array=(hello)

Which yielded

Quote:

myscript.sh 3: Syntax error: "(" unexpected

What am I doing wrong with my syntax when using the array() command?

colucix 03-08-2011 03:36 AM

Quote:

Originally Posted by greengrocer (Post 4282488)
What am I doing wrong with my syntax when using the array() command?

Nothing wrong! Please check which shell you're actually using and show us the output of the following commands:
Code:

readlink -f /bin/bash
bash --version


greengrocer 03-08-2011 03:51 AM

Output of readlink -f /bin/bash

Code:

/bin/bash

Output of bash --version

Code:

GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.


colucix 03-08-2011 04:03 AM

Well... it sounds good. However I think there is a problem with the fact that Ubuntu uses /bin/dash as the default shell and for some reason the sha-bang #!/bin/bash is skipped. In other words it looks like the script is executed by the dash shell and the array assigment is buggy in some way. Just a guess, but I found confirmation on the Ubuntu forums, here (see in particular post #5). By the way, how did you run the script? Does
Code:

bash scriptname.sh
make a difference?

greengrocer 03-08-2011 04:14 AM

Yes you're right.

The sha-bang was being skipped when I invoke my script using sh myscript.sh

So instead I tried:

Code:

./myscript.sh
Which worked (but first I had to chmod 755 myscript.sh).

colucix 03-08-2011 04:27 AM

Indeed when the shell is invoked as interactive (for example when the standard input is connected to a terminal and you don't use the -c option) the sha-bang is treated as a comment. The question now is: how does /bin/dash manage arrays? What are the differences between the /bin/bash syntax and /bin/dash? I cannot find any exhaustive documentation on the net. Maybe someone here can shed some light. :jawa:

Edit: I found some information on Greg's Wiki: http://mywiki.wooledge.org/Bashism which simply states that
Quote:

Arrays are not defined by posix (but are present in ksh); there is no easy general workaround for arrays.
but it still doesn't tell anything about the exact dash behaviour.

greengrocer 03-08-2011 04:40 AM

Almost there.

My script is:

Code:

#!/bin/bash

array=("$@")
len=${#array[*]}
echo "The array has $len members. They are:"
i=0
while [ $i -lt $len ]; do
        parameter$i=${array[$i]}
        echo "${parameter[$i]}"
        let i++
done

When I invoke my script using:

Quote:

./myscript.sh alpha bravo charlie
I get the following output:

Code:

The array has 3 members. They are:
./myscript.sh: line 8: parameter0=alpha: command not found

./myscript.sh: line 8: parameter1=bravo: command not found

./myscript.sh: line 8: parameter2=charlie: command not found

What I really want is echo "${parameter[$i]}" to deliver output as:

Code:

The array has 3 members. They are:
alpha
bravo
charlie

Where:
parameter1 = alpha
parameter2 = bravo
parameter3 = charlie


I know I am close to the solution but my knowledge of manipulating variables is weak.

colucix 03-08-2011 05:33 AM

Code:

        parameter$i=${array[$i]}
        echo "${parameter[$i]}"

It's not really clear what you're trying to do here. This code tries to assign scalar variables parameter0, parameter1, parameter2 then it tries to print them as array elements. In any case waht you need is indirect reference where the name of a variable is referenced by another variable. Here is a working example using eval:
Code:

i=1
while [ $i -lt $len ]; do
        eval parameter$i=${array[$i]}
        eval echo \$parameter$i
        let i++
done

Please see http://www.tldp.org/LDP/abs/html/abs-guide.html#IVR for more details about indirect reference.

Anyway, if you need to assign the positional parameters to scalar variables, the array step is superfluous. Here is two alternatives:
Code:

#!/bin/bash
i=1
while [[ $i -le $# ]]
do
  eval parameter$i=\$$i
  eval echo \$parameter$i
  (( i++ ))
done

or using shift
Code:

#!/bin/bash
i=1
until [[ -z $1 ]]
do
  eval parameter$i=$1
  eval echo \$parameter$i
  shift
  (( i++ ))
done

I would stick with arrays anyway, since indirect reference might be confusing. Furthermore the eval statement can be dangerous in some situations.

grail 03-08-2011 06:49 AM

So I will start with, I am not really sure what the objective is here?
The reason i said this is because unless you need the separate storage, ie array, for another reason, why not just use the positional parameters as they lay?

$# will give you the number of parameters passed in and the same as using say array[1] you can just use $2 (as arrays start at 0 unless otherwise defined).

So to use your current example:
Code:

#!/bin/bash

echo "$# members were passed in. They are:"

for ARG
do
    echo $ARG
done

Output:
Code:

$ ./myscript.sh alpha bravo charlie
3 members were passed in. They are:
alpha
bravo
charlie


ntubski 03-08-2011 10:38 AM

Quote:

Originally Posted by colucix (Post 4282528)
The question now is: how does /bin/dash manage arrays? What are the differences between the /bin/bash syntax and /bin/dash? I cannot find any exhaustive documentation on the net. Maybe someone here can shed some light. :jawa:

Edit: I found some information on Greg's Wiki: http://mywiki.wooledge.org/Bashism which simply states that
Quote:

Arrays are not defined by posix (but are present in ksh); there is no easy general workaround for arrays.
but it still doesn't tell anything about the exact dash behaviour.

dash doesn't support arrays, it's supposed to be a shell with the minimum number of features needed for POSIX compliance.

greengrocer 03-10-2011 02:20 AM

OK, I'm starting to see what you mean about an array perhaps being the most appropriate method for what I want to do because while the array is storing the parameters that were specified when my script is invoked, I can step through the array, locate a parameter and act upon it using while and if loops.

grail 03-10-2011 08:37 AM

Quote:

OK, I'm starting to see what you mean about an array perhaps being the most appropriate method for what I want to do because while the array is storing the parameters that were specified when my script is invoked, I can step through the array, locate a parameter and act upon it using while and if loops.
That and the fact that eval is often pronounced 'evil' as it can cause some serious headaches ... especially if it gets out of control.

scurveedog 04-11-2011 03:24 PM

maybe a case where you can deal with any or all parameters?

Code:

#!/bin/bash

while test $# -gt 0; do
        case "$1" in
                red)
                        echo "$1"
                        # code for red param
                shift;;

                green)
                        echo "$1"
                        # code for green param
                shift;;
               
                blue)
                        echo "$1"
                        #code for blue param
                shift;;

                *)
                        echo "Not in parameter list"
                        # or code to handle case of no or non-listed param
                exit 1;;
        esac
done

as is, the case will exit as soon as a non-listed parameter is found.


All times are GMT -5. The time now is 07:31 PM.