LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   General (http://www.linuxquestions.org/questions/general-10/)
-   -   BASH script using getopt to parse optional arguments (http://www.linuxquestions.org/questions/general-10/bash-script-using-getopt-to-parse-optional-arguments-877176/)

nano2 04-26-2011 10:15 AM

BASH script using getopt to parse optional arguments
 
Hi
i have the following scenario want to run the following script with manadory and optional argumnets

Manadory options are :

filename=""
port=""
optional arguments

type -t [A/B]
balances -b bal
prices -p

./test filename port -t A -b bal


my code i have that won't parse the options is
This is what i have
#!/bin/bash
filename=""
port=""

while getopts b:t:p opt
do
case $opt in
b) BAL="${OPTARG}"
if [ "$BAL" == "" ]
then
print_usage $0
else
echo "Balances is " $BAL
fi ;;

t) TYPE="$OPTARG";;
p) PRICES="$OPTARG";;
?) print_usage $0
exit 1;;
esac
done
echo "Balances: "$BAL
echo "Type: "$TYPE


Any ideas
~

catkin 04-26-2011 12:05 PM

First idea is to use CODE tags to make your code more readable; you can most easily use them by changing to advanced mode posting and using the # button.

Copying your code into CODE tags:
Code:

#!/bin/bash
filename=""
port=""

while getopts b:t:p opt
 do
      case $opt in
          b) BAL="${OPTARG}"
            if [ "$BAL" == "" ]
            then
                print_usage $0
            else
                echo "Balances is " $BAL
            fi ;;

          t) TYPE="$OPTARG";;
          p) PRICES="$OPTARG";;
          ?) print_usage $0
            exit 1;;
      esac
done
echo "Balances:                "$BAL
echo "Type:                    "$TYPE

Second idea is to explain exactly what "won't parse the options" means, for example by copying and pasting the output into this thread.

Guessing what the problem is, getopts is traditional; it must have the options (and option arguments) before the arguments. Try
Code:

./test -t A -b bal filename port

David the H. 04-26-2011 12:35 PM

You also have to shift the parameters after processing the optional arguments so you can grab what's left.
Code:

while getopts b:t:p opt ; do
...
done

shift $(( OPTIND-1 ))

filename="$1"
port="$2"

This is a decent getopts tutorial:
http://wiki.bash-hackers.org/howto/getopts_tutorial

Edit: Thinking about it, It is possible instead to have the mandatory arguments first, if you really want it that way. Just reverse the above: set filename and port first, then shift the parameters by two so that the getopts loop can process the rest.

The thing you can't do is mix the two types arbitrarily. The getopts arguments pretty much have to come together as a group.

Not without some funky coding magic at least.

nano2 04-27-2011 03:36 AM

Yes I have tried this inorder to place the manadory options first and then shift by 2 But I get the following error
-2: shift count out of range

Any ideas what i am doing wrong !

while getopts b:t:p opt ; do
...

done
filename="$1"
port="$2"

shift $(( OPTIND-2 ))

David the H. 04-27-2011 09:11 AM

1) As catkin asked above, please use [code][/code] tags around your code, to preserve formatting and to improve readability.

2) As I said, you have to reverse the process. Save the first two parameters to variables first, then shift 2 to remove them from the command list, then use getopts on the rest.
Code:

filename="$1"
port="$2"

shift 2

while getopts ...

Be aware that this means filename and port must always come first, and in that order, since they are processed first in the code and then their parameters are discarded.

Again, this just reverses the traditional pattern, where the getopts options are processed first, and discarded, so that whatever is left can be used in other ways.

Look at the link I gave you and carefully read how getopts works. Look up what shift does too if necessary (hint, there's a link to "handling positional parameters" on that page that explains it, along with other useful info related to this topic).

Or you could just give the "mandatory" arguments their own getopts flags too, then you wouldn't have to worry about the order they come in at all.

nano2 04-27-2011 04:17 PM

David ,
how could I achieve this inside the getopts would i need to pass in aoption for the filename etc
eg -f ?

" you could just give the "mandatory" arguments their own getopts flags too, then you wouldn't have to worry about the order they come in at all. "

Code:


while getopts b:t:p opt


David the H. 04-28-2011 09:09 AM

Yes, just give them their own flags.

What makes an option "mandatory" or "optional" is not whether it has a getopts flag, it's all in what tests you run when and after you process the parameter. All getopts does is provide an easy way to have a flag-style input.

So, just add a "f:" to flags list, and use that to set the filename variable inside the getopts loop. Then after finishing getopts, run a test on that variable to see if the file exists. If it doesn't, throw up an error.
Code:


while getopts b:t:f:P:p opt ; do

  ...
  -f) filename=$OPTARG ;;
  -P) port=$OPTARG ;;
  ...

done

if [[ -z $filename  ]] ; then

  echo "A filename must be supplied (with the "-f" flag)."
  exit 1

elif [[ ! -e $filename ]]; then

  echo "The filename provided does not exist."
  exit 1

elif [[ ! -r $filename ]]; then

  echo "The filename provided is not readable.  Check your permissions."
  exit 1
fi

...and so on..


All times are GMT -5. The time now is 05:37 PM.