1

I have a loop to parse command line arguments. Everything works fine if -d or -b argument has a parameter. But when I pass -d or -b without a parameter, the script gets into infinite loop.

# Parse command line input
while [ "$#" -gt 0 ]; do
  case "$1" in
    -d) DOMAIN="$2"; shift 2;;
    -b) BITS="$2"; shift 2;;
     *) die "unrecognized argument: $1"
  esac
done

How to throw error on empty parameter?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Paweł Madej
  • 1,229
  • 23
  • 42
  • 3
    If your arguments are just single-letter, you can use [`getopts`](https://www.gnu.org/software/bash/manual/bashref.html#index-getopts) instead of rolling your own. – Benjamin W. Jan 17 '17 at 23:28
  • 1
    One trick that would work, especially if you had some flag options (that don't take arguments) is `shift` instead of `shift 2` inside the `case`, and another `shift` after `esac` and before `done`. The flag options wouldn't need a shift at all. Because it would shift one argument at a time, it would get rid a stray `-b` with no argument, so the loop would terminate. That said, the `getopts` answer is the better long-term choice. Ad hoc solutions acquire ad hoc bugs — witness your infinite loop problem. – Jonathan Leffler Jan 18 '17 at 00:21

3 Answers3

2

The shift n command doesn't do anything if you try to shift more than the number of values present in the list. That's the reason for the infinite loop in your code.

Using getopts is the right thing to do as it gives you a lot of flexibility. Otherwise, you could rewrite your loop this way:

#!/bin/bash
# Parse command line input
d_flag=0
b_flag=0
while [ "$#" -gt 0 ]; do
  case "$1" in
    -d) 
        d_flag=1
        shift
        [[ $1 == -* ]] && continue # argument to -d not given
        DOMAIN=$1
        shift
        ;; 
    -b) 
        b_flag=1
        shift
        [[ $1 == -* ]] && continue # argument to -b not given
        BITS=$1
        shift
        ;;
     *) echo "unrecognized argument: $1"; exit 2;;
  esac
done

if [[ $d_flag = 1 && -z $DOMAIN ]]; then
    # handle error - option requires an argument
fi

if [[ $b_flag = 1 && -z $BITS ]]; then
    # handle error - option requires an argument
fi
codeforester
  • 39,467
  • 16
  • 112
  • 140
2

Shift fails due to not enough arguments.

This problem would, however, be immediately obvious is you set your shell to fail on all errors (with set -e). It makes debugging much easier in many cases by avoiding silent failures, and enforces discipline and error checking. set -u causes errors on failed variable expansions, also very useful.

Fred
  • 6,590
  • 9
  • 20
0

Since it seems you always need two parameters you could change first line to:

while [ "$#" -eq 2 ]; do

Otherwise you can check the value of $2 before to enter the loop like this:

if [[ -z $2 ]]; then 
echo "missing second parameter"
else
#do the while loop
fi
George Vasiliou
  • 6,130
  • 2
  • 20
  • 27