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
  • 2
    Why reinvent the wheel? bash has a builtin getopts Commented Aug 27, 2016 at 13:46
  • Creating this code is my purpose. Commented Aug 27, 2016 at 13:52

2 Answers 2

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.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.