Skip to main content
edited body
Source Link
Chris Davies
  • 128.4k
  • 16
  • 179
  • 324

Finally, if the code is in the file myscript, don't run it as bash myscript. Instead set the file to be readable/executable (chmod a=rxa+rx myscript) and just run it directly (./myscript). The first line tells the system what interpreter to use so there's no need to specify bash explicitly when running it.

Finally, if the code is in the file myscript, don't run it as bash myscript. Instead set the file to be readable/executable (chmod a=rx myscript) and just run it directly (./myscript). The first line tells the system what interpreter to use so there's no need to specify bash explicitly when running it.

Finally, if the code is in the file myscript, don't run it as bash myscript. Instead set the file to be readable/executable (chmod a+rx myscript) and just run it directly (./myscript). The first line tells the system what interpreter to use so there's no need to specify bash explicitly when running it.

Example code
Source Link
Chris Davies
  • 128.4k
  • 16
  • 179
  • 324

No point using $@ because (a) you didn't double-quote it, and (b) you're writing a string rather than a series of values. (Look up the difference between $*, $@, and "$@" if you don't follow this). Finally, I told getopt to report errors on behalf on your program. The ${0##*/} construct picks out the program name for you:

>&2 echo "[$*] passed to script"

if ! args=$(getopt -n "${0##*/}" -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
then
  usage
fi

>&2 echo "getopt creates [$args]"
eval set -- "$args"
while :
do
  case $1 in
    -a | --user_type)   user_type=$2    ; shift 2  ;;
    -b | --user_id)    user_id=$2     ; shift 2  ;;
    -h | --help)    usage      ; shift   ;;
    -c | --country)   country=$2   ; shift 2 ;;
    -d | --dev_env)   dev_env=$2   ; shift 2 ;;
    -e | --position_id) position_id=$2 ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    *) >&2 echo "Unsupported option: $1"
       usage ;;
  esac
done

The shift statements (above) eat the arguments as they're processed. But in a moment you want to print the remaining arguments, so there's no point bailing with a usage error if there are none left. Code removed.

Also above, I've removed the error condition in the case because it's already handled directly by getopt.

# Output the remaining parameters
for param in "$@"; do
   >&2 echo -e "\t$param"
done

echo "user ${user_type:-<unset>} with user id ${user_id:-<unset>} has been created with position_id ${position_id:-<unset>}"
exit 0

Finally, if the code is in the file myscript, don't run it as bash myscript. Instead set the file to be readable/executable (chmod a=rx myscript) and just run it directly (./myscript). The first line tells the system what interpreter to use so there's no need to specify bash explicitly when running it.

Example:

./myscript --user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf

[--user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf] passed to script
getopt creates [ --user_type 'abc' --user_id 'a1b2' --country 'aud' --dev_env 'uat' --position_id 'aFWf' --]
user_type   : abc
user_id    : a1b2
country   : aud
dev_env   : uat
position_id   : aFWf
0 parameter/s remaining:
Looping through remaining parameter/s:
user abc with user id a1b2 has been created with position_id aFWf

No point using $@ because (a) you didn't double-quote it, and (b) you're writing a string rather than a series of values. (Look up the difference between $*, $@, and "$@" if you don't follow this):

>&2 echo "[$*] passed to script"

if ! args=$(getopt -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
then
  usage
fi

>&2 echo "getopt creates [$args]"
eval set -- "$args"
while :
do
  case $1 in
    -a | --user_type)   user_type=$2    ; shift 2  ;;
    -b | --user_id)    user_id=$2     ; shift 2  ;;
    -h | --help)    usage      ; shift   ;;
    -c | --country)   country=$2   ; shift 2 ;;
    -d | --dev_env)   dev_env=$2   ; shift 2 ;;
    -e | --position_id) position_id=$2 ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    *) >&2 echo "Unsupported option: $1"
       usage ;;
  esac
done

The shift statements (above) eat the arguments as they're processed. But in a moment you want to print the remaining arguments, so there's no point bailing with a usage error if there are none left. Code removed.

# Output the remaining parameters
for param in "$@"; do
   >&2 echo -e "\t$param"
done

echo "user ${user_type:-<unset>} with user id ${user_id:-<unset>} has been created with position_id ${position_id:-<unset>}"
exit 0

No point using $@ because (a) you didn't double-quote it, and (b) you're writing a string rather than a series of values. (Look up the difference between $*, $@, and "$@" if you don't follow this). Finally, I told getopt to report errors on behalf on your program. The ${0##*/} construct picks out the program name for you:

>&2 echo "[$*] passed to script"

if ! args=$(getopt -n "${0##*/}" -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
then
  usage
fi

>&2 echo "getopt creates [$args]"
eval set -- "$args"
while :
do
  case $1 in
    -a | --user_type)   user_type=$2    ; shift 2  ;;
    -b | --user_id)    user_id=$2     ; shift 2  ;;
    -h | --help)    usage      ; shift   ;;
    -c | --country)   country=$2   ; shift 2 ;;
    -d | --dev_env)   dev_env=$2   ; shift 2 ;;
    -e | --position_id) position_id=$2 ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
  esac
done

The shift statements (above) eat the arguments as they're processed. But in a moment you want to print the remaining arguments, so there's no point bailing with a usage error if there are none left. Code removed.

Also above, I've removed the error condition in the case because it's already handled directly by getopt.

# Output the remaining parameters
for param in "$@"; do
   >&2 echo -e "\t$param"
done

echo "user ${user_type:-<unset>} with user id ${user_id:-<unset>} has been created with position_id ${position_id:-<unset>}"
exit 0

Finally, if the code is in the file myscript, don't run it as bash myscript. Instead set the file to be readable/executable (chmod a=rx myscript) and just run it directly (./myscript). The first line tells the system what interpreter to use so there's no need to specify bash explicitly when running it.

Example:

./myscript --user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf

[--user_type abc --user_id a1b2 --country aud --dev_env uat --position_id aFWf] passed to script
getopt creates [ --user_type 'abc' --user_id 'a1b2' --country 'aud' --dev_env 'uat' --position_id 'aFWf' --]
user_type   : abc
user_id    : a1b2
country   : aud
dev_env   : uat
position_id   : aFWf
0 parameter/s remaining:
Looping through remaining parameter/s:
user abc with user id a1b2 has been created with position_id aFWf
Source Link
Chris Davies
  • 128.4k
  • 16
  • 179
  • 324

Here you go, a working version of your code. I'll break out every-so-often to try and explain why I've changed what I've changed

#!/bin/bash
#
# Adapted from https://www.shellscript.sh/examples/getopt/
#

I prefer to initialise variables to an empty value, and then substitute text inside error messages if necessary. Your user_type=unset could work, setting the variable to the text unset but it prevents simple tests later on such as if [ -z "$user_type ]; then echo "the variable user_type has no value"; fi, and definitely breaks if the user supplies unset as a literal value:

user_type=
user_id=
country=
dev_env=
position_id=

usage(){
>&2 cat << EOF
Usage: $0]
   [ -a | --user_type input
   [ -b | --user_id input ]
   [ -c | --country input ]
   [ -d | --dev_env input ]
   [ -e | --position_id input ]
EOF
exit 1
}

No point using $@ because (a) you didn't double-quote it, and (b) you're writing a string rather than a series of values. (Look up the difference between $*, $@, and "$@" if you don't follow this):

>&2 echo "[$*] passed to script"

if ! args=$(getopt -a -o ha:b:c:d: --long help,user_type:,user_id:,country:,dev_env:,position_id: -- "$@")
then
  usage
fi

>&2 echo "getopt creates [$args]"

Don't forget the double quotes around $args:

eval set -- "$args"
while :
do
  case $1 in
    -a | --user_type)   user_type=$2    ; shift 2  ;;
    -b | --user_id)    user_id=$2     ; shift 2  ;;
    -h | --help)    usage      ; shift   ;;
    -c | --country)   country=$2   ; shift 2 ;;
    -d | --dev_env)   dev_env=$2   ; shift 2 ;;
    -e | --position_id) position_id=$2 ; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    *) >&2 echo "Unsupported option: $1"
       usage ;;
  esac
done

The shift statements (above) eat the arguments as they're processed. But in a moment you want to print the remaining arguments, so there's no point bailing with a usage error if there are none left. Code removed.

In this next section, variables such as $user_type may be unset, so they'll have no value. Here the ${user_type:-<unset>} displays <unset> if the value is unset/empty:

>&2 echo "user_type   : ${user_type:-<unset>}"
>&2 echo "user_id    : ${user_id:-<unset>} "
>&2 echo "country   : ${country:-<unset>}"
>&2 echo "dev_env   : ${dev_env:-<unset>}"
>&2 echo "position_id   : ${position_id:-<unset>}"
>&2 echo "$# parameter/s remaining: $*"
>&2 echo "Looping through remaining parameter/s:"

Double-quote the "$@" so that words are treated as single elements even if they originally contained whitespace:

# Output the remaining parameters
for param in "$@"; do
   >&2 echo -e "\t$param"
done

echo "user ${user_type:-<unset>} with user id ${user_id:-<unset>} has been created with position_id ${position_id:-<unset>}"
exit 0