2

I'm trying to create a bash script and take in 2 options

  • bePort and fePort

since this is working

while getopts ":a:b:" opt; do
  case $opt in
    a)
      echo "-a was triggered!, Parameter: $OPTARG" >&2
      ;;
    b)
      echo "-b was triggered!, Parameter: $OPTARG" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done

I run

bash test.sh -a aaa -b bbb

I got

-a was triggered!, Parameter: aaa
-b was triggered!, Parameter: bbb

So then, I've tried this

while getopts ":fe:be:" opt; do
  case $opt in
    fe)
      echo "-fe was triggered!, Parameter: $OPTARG" >&2
      ;;
    be)
      echo "-be was triggered!, Parameter: $OPTARG" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done

But it doesn't seem to work.

I run

bash test.sh -fe 4444 -be 3333

I got nothing printing in my prompt.

I was expecting to see something like this

-be was triggered!, Parameter: 3333
-fe was triggered!, Parameter: 4444

How would one go about debugging this further?

halfer
  • 19,824
  • 17
  • 99
  • 186
code-8
  • 54,650
  • 106
  • 352
  • 604
  • If you want to handle `-fe` as a single option, consider using the pattern described in [BashFAQ #35](https://mywiki.wooledge.org/BashFAQ/035) instead of `getopts` to build your own parsing. – Charles Duffy May 02 '18 at 19:54
  • ...that said, this is not standard practice -- see [POSIX utility syntax guidelines](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html), specifically guideline #5: *One or more options without option-arguments, followed by at most one option that takes an option-argument, should be accepted when grouped behind one '-' delimiter.*; and guideline #3: *Each option name should be a single alphanumeric character (the alnum character classification) from the portable character set. The -W (capital-W) option shall be reserved for vendor options.* – Charles Duffy May 02 '18 at 19:55
  • to make a long story short... you get one letter – Jose Martinez May 02 '18 at 19:58
  • 1
    If you want long (multiletter) options, the standard is to use a double-dash and separate the value with "=" (as in `grep --color=always`). But `getopts` only handles single-letter options, so you need to use something else. Either that, or switch to single-letter options. Frankly, two-letter options are rather weird. – Gordon Davisson May 02 '18 at 21:42

1 Answers1

5

It because -fe 4444 is parsed as -f -e 4444.

Test code:

while getopts ":fe:be:" opt; do
  case $opt in
    b)
      echo "-b was triggered!, Parameter: $OPTARG" >&2
      ;;
    e)
      echo "-e was triggered!, Parameter: $OPTARG" >&2
      ;;
    f)
      echo "-f was triggered!, Parameter: $OPTARG" >&2
      ;;
    fe)
      echo "-fe was triggered!, Parameter: $OPTARG" >&2
      ;;
    be)
      echo "-be was triggered!, Parameter: $OPTARG" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
  esac
done

Output:

$ bash test.sh -fe 4444 -be 3333
-f was triggered!, Parameter: 
-e was triggered!, Parameter: 4444
-b was triggered!, Parameter: 
-e was triggered!, Parameter: 3333

It is appropriate to use long options like --fe 4444. How to parse long options with bash have been answered at another post.

-> Using getopts in bash shell script to get long and short command line options

set0gut1
  • 1,652
  • 1
  • 8
  • 21
  • what did you do that I didn't do ? could n't seem to spot it. – code-8 May 02 '18 at 19:55
  • @kyo, the code here accepts `-f` and `-e` as separate options, which is how getopts handles `-fe` (as one `-f` followed by a `-e`). You'll notice that the `fe` and `be` cases are never called in the example output, but it has `-f` output, then `-e` output, then `-b` output, then `-e` output again. – Charles Duffy May 02 '18 at 19:56
  • Your code does not handle `be` and `fe` together that is my original question. – code-8 May 02 '18 at 19:58
  • I stil wondering what is the best way to parse long option with bash... – set0gut1 May 02 '18 at 20:04
  • 3
    @set0gut1 There is no built-in way. Either parse the argument completely manually (by iterating over `"$@"` yourself), or use a third-party library. – chepner May 02 '18 at 21:25