9

I was trying to modify the bd script to use getopts. I am a newbie at bash scripting

my script is

while getopts ":hvis:d:" opt
do
...
done

...

echo $somedirpath
cd "$somedirpath"    

this runs fine when doing

$ ./bd -v -i -s search

or

$ ./bd -is search -d dir

But when running it like this

$ . ./bd -s search

getopts doesn't read the arguments at all. And all the variables I set in the while loop according to the arguments are all not set, so the script no longer works. Please help!

udiboy1209
  • 1,472
  • 1
  • 15
  • 33

3 Answers3

10

Setting OPTIND=1 before invoking getopts works fine.

The problem is that getopts relies on OPTIND to loop through the arguments provided, and after sourcing the script, it will be set to some value greater than 1 by getopts according to how many arguments you pass. This value gets carried over even after the script ends(because its being sourced). So the next time its sourced, getopts will pick up from that OPTIND, rather than starting from 1!

This might cause strange behaviour with other scripts, and I don't know how safe this is. But it works!

For a better workaround, I think what @tripleee suggests looks safe and robust.

udiboy1209
  • 1,472
  • 1
  • 15
  • 33
6

When you source a script, the arguments parsed by getopts are those of the current shell, not the parameters on the source command line.

The common workaround is to have your script merely print the path, and invoke it like cd "$(bd)" instead (perhaps indirectly through a function or alias).

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 1
    But `echo "$@"` shows me the correct args, even when sourcing the script? – udiboy1209 May 10 '14 at 13:54
  • Plus, that won't react to error statements from the script very well. – udiboy1209 May 10 '14 at 14:01
  • @tripleee: from `help source`: "If any ARGUMENTS are supplied, they become the positional parameters when FILENAME is executed." In other words, inside the sourced script, the arguments are inherited *if you didn't specify any arguments* to the `source` command; otherwise, you do indeed get the specified arguments. – rici May 10 '14 at 19:00
  • (Yes, it's a bash extension. Also a ksh extension. And probably others. The question is tagged bash.) – rici May 10 '14 at 19:03
  • The script behind the Github link has a `#!/bin/sh` shebang line, so I guess actually the tag is wrong. But thanks for the additional information. – tripleee May 11 '14 at 07:05
  • somehow setting `OPTIND` to `1` before invoking getopts seems to work fine. But I took to a different approach entirely, which does not use `getopts`. Thanks for your help anyway – udiboy1209 May 12 '14 at 17:39
0

Setting OPTIND=1 may not work reliably on zsh. Try to use something different than getopts:

while [ "$#" -gt 0 ]
do
   case "$1" in
   -h|--help)
      help
      return 0
      ;;
   -o|--option)
      option
      return 0
      ;;
   -*)
      echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2
      return 1
      ;;
   *)
      echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2
      return 1
   ;;
   esac
   shift
done
t7e
  • 322
  • 1
  • 3
  • 9