0

I am writing a shell script which accepts at most 2 options. However, I have a problem. Could you help me with it? (Let's say the name of this script is command.)

#!/bin/bash
PROGNAME=$(basename $0)
for OPT in "$@"
do
    echo "OPT: $OPT"
    case "$OPT" in
            '-p' | '--password' )
                    if [[ -z "$2" ]] || [[ "$2" =~ ^-+ ]]
                    then
                            echo "$PROGNAME: option requires an argument -- '$(echo $1 | sed 's/^-*//')'"
                            exit 2
                    fi
                    PASSWORD="$2"
                    shift 2
                    ;;
            '-u' | '--user' )
                    if [[ -z "$2" ]] || [[ "$2" =~ ^-+ ]]
                    then
                            echo "$PROGNAME: option requires an argument -- '$(echo $1 | sed 's/^-*//')'"
                            exit 2
                    fi
                    USER="$2"
                    shift 2
                    ;;
            * )
                    echo "$1"
                    echo "$PROGNAME: illigal option or argument -- '$(echo $1 | sed 's/^-*//')'"
                    exit 1
                    ;;
    esac
done
echo "GOOD"

Test1

$./command 
GOOD

Test2

$./command -u user
OPT: -u
OPT: user

command: illigal option or argument -- ''

(The fourth line is empty.)

Test3

$./command -u user -p passwd
OPT: -u
OPT: user
-p
command: illigal option or argument -- 'p'

Same things happens to all -u, --user, -p and --password. I have 3 questions.

1) Why does "OPT: user" show up in test2 and test3?

2) Why does this code cause errors if I give one option to it?

3) How can I fix this code? I really appreciate your help!

  • 2
    Why reinvent the wheel? bash has a builtin getopts – steeldriver Aug 27 '16 at 13:46
  • Creating this code is my purpose. – Nickel Aug 27 '16 at 13:52
1

Your expansion of "$@" happens at the beginning of the for loop; the shift inside it won't have any impact.

eg

for a in "$@"
do
  echo OPTION: $a
  shift 2
done

With this:

$ bash x a b c d e f
OPTION: a
OPTION: b
OPTION: c
OPTION: d
OPTION: e
OPTION: f

We can see the shift isn't doing anything

Instead you want to re-evaluate it each time:

$ cat x             
while [ $# -gt 0 ]
do
  a="$1"
  echo OPTION: $a
  shift 2
done

$ bash x a b c d e f
OPTION: a
OPTION: c
OPTION: e

(You need to do a better test than this; this example code never terminates if you pass an odd number of arguments 'cos the shift 2 fails)

0

I use to use a while/shift loop

#! /bin/bash
PROGNAME=$(basename $0)
while [ -n "$1" ]
do
  echo "OPT: $1"
  case "$1" in
    --user=* )
      if [[ "$1" =~ --user=(.+) ]]
      then
        USER=${BASH_REMATCH[1]}
      else
        echo "$PROGNAME: option requires an argument -- $1"
        exit 2
      fi
      ;;
    -u )
      if [ -z "$2" ]
      then
        echo "$PROGNAME: option requires an argument -- $1"
        exit 2
      fi
      USER="$2"
      shift
      ;;
    * )
      echo "$PROGNAME: illigal option or argument -- $1"
      exit 1
      ;;
  esac
  shift
done
[ -n "$USER" ] && echo "USER: $USER"
echo "GOOD"

But $USER is a bad variable since it is already set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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