2

I am trying to pass some values to my bash script using named parameters similar to the following:

./script.sh --username='myusername' --password='superS3cret!' --domainou="OU=Groups with Space,OU=subou,DC=mydomain,DC=local"

I have the following code:

#!/bin/bash

while [ "$1" != "" ]; do
    PARAM=`echo $1 | awk -vFPAT='([^=]*)|("[^"]+")' -vOFS="=" '{print $1}'`
    VALUE=`echo $1 | awk -vFPAT='([^=]*)|("[^"]+")' -vOFS="=" '{print $2}'`
    case $PARAM in
        -u | --username)
            username=$VALUE
            ;;
        -p | --password)
            password=$VALUE
            ;;
        -ou | --domainou)
            domainou=$VALUE
            ;;
        *)
            echo "ERROR: unknown parameter \"$PARAM\""
            exit 1
            ;;
    esac
    shift
done

echo $username
echo "$password"
echo "$domainou"

What I get when I run my script is:

myusername
superS3cret!
OU

Now the first two lines are correct but obviously I don't want OU... I want:

OU=Groups with Space,OU=subou,DC=mydomain,DC=local

Awk seems to be matching the = inside the quote. As best as I can tell the way to solve that is using

-vFPAT='([^=]*)|("[^"]+")' -vOFS="=" 

But clearly that's not working so I am just wondering if any awk gurus can help me understand what's wrong with my awk statement.

Thanks Brad

Brad
  • 1,979
  • 7
  • 35
  • 47
  • 2
    You don't need `awk` here. You can replace the two lines, which attempt to extract the parameter-value pairs, with `PARAM=${1%%=*}` and `VALUE=${1#*=}` using plain bash. – M. Nejat Aydin Aug 30 '20 at 04:06
  • 3
    Awk never sees the quotation marks, since they are part of shell *syntax*. Experimenting with`echo` (and/or `printf`) might clarify how shell processing works. – rici Aug 30 '20 at 04:15
  • there is a tool named `getopt` that helps you parsing long options. – Marco Aug 30 '20 at 06:44
  • Does this answer your question? [How do I parse command line arguments in Bash?](https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash) – Marco Aug 30 '20 at 06:59
  • 1
    Copy/paste your script into http://shellcheck.net and fix the issues it tells you about. – Ed Morton Aug 30 '20 at 12:24

3 Answers3

3

You can do it like this:

#!/bin/bash

while [ $# -gt 0 ]; do
  case "$1" in
    -u=* | --username=*)
      username="${1#*=}"
      ;;
    -p=* | --password=*)
      password="${1#*=}"
      ;;
    -ou=* | --domainou=*)
      domainou="${1#*=}"
      ;;
    *)
      printf "Error: unknown option: $1\n"
      exit 1
  esac
  shift
done

printf "username: $username\n"
printf "password: $password\n"
printf "domainou: $domainou\n"

1218985
  • 7,531
  • 2
  • 25
  • 31
1

For parsing command line options that include both long and short optoins, consider using GNU getopt, which has support for long options. While it is possible to build-your-own parser replacement, using the getopt provides for more robust parsing:

  • Abbreviation of options (e.g., accepting --user for --username).
  • Checking for required/optional values
  • Error handling

See also: Using getopts to process long and short command line options

set $(getopt --long 'username:,password:,ou:,domain:' -o 'u:p:' -- "$0" "$@")
while [ "$#" -gt 0 ] ; do
    OP=$1
    shift
    case "$OP" in
        --) PROG=$1 ; shift ; break ;;
        -u | --username) username=$1 ; shift ;;
        -p | --password) password=$1 ; shift ;;
        --ou | --domain) domainou=$1 ; shift ;;
    esac
done
# Positional arguments are set ...
dash-o
  • 13,723
  • 1
  • 10
  • 37
0

Below is what ultimately worked best for me.

@dash-o definitely got me pointed in the right direction but the script you provided was printing out extraneous info:

set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]

I believe the offending line was this:

set --long 'username:,password:,ou:,domain:' -o 'u:p:' -- "$0" "$@"

Here's the code that accomplished what I needed. I can't take credit for this. I stole it from here Using getopts to process long and short command line options but I never would have found that if not for dash-o so a big thank you!

#!/bin/bash
die() { echo "$*" >&2; exit 2; }  # complain to STDERR and exit with error
needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }

while getopts u:p:o:-: OPT; do
  # support long options: https://stackoverflow.com/a/28466267/519360
  if [ "$OPT" = "-" ]; then   # long option: reformulate OPT and OPTARG
    OPT="${OPTARG%%=*}"       # extract long option name
    OPTARG="${OPTARG#$OPT}"   # extract long option argument (may be empty)
    OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
  fi
  case "$OPT" in
    u | username )  needs_arg; username="$OPTARG" ;;
    p | password )  needs_arg; password="$OPTARG" ;;
    o | domainou )  needs_arg; domainou="$OPTARG" ;;
    ??* )          die "Illegal option --$OPT" ;;  # bad long option
    \? )           exit 2 ;;  # bad short option (error reported via getopts)
  esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list

echo "$username"
echo "$password"
echo "$domainou"
Adam Katz
  • 14,455
  • 5
  • 68
  • 83
Brad
  • 1,979
  • 7
  • 35
  • 47