Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I use getopts to parse arguments in bash scripts as

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparams will hold any unparsed options/arguments. Since I want to use exeparams to hold options for a command to be executed within the script (which can overlap with the scripts own options), I want to use -- to end the options passed to the script. If I pass e.g.

myscript -d myscriptparam -- -d internalparam

exeparams will hold

-- -d internalparam

I now want to remove the leading -- to pass these arguments to the internal command. Is there an elegant way to do this or can I obtain a string which holds just the remainder without -- from getopts?

share|improve this question
    
Putting shift; OPTIND=1 inside the getopts loop is probably not the best way to do it. It only works in your case because you only have 2 options and in all the other ones you just exit the script. Otherwise you'd need shift; OPTIND=1 in every option, which means duplicate code (bad practice). Just do a shift $((OPTIND - 1)) immediately after the end of the loop - this is the most conventional way and probably the most efficient as well. –  jw013 Nov 14 '12 at 22:40
add comment

2 Answers 2

up vote 2 down vote accepted

How about:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Note, you should use an array to hold the parameters. That will properly handle any arguments containing whitespace. Dereference the array with "${exeparams[@]}"

share|improve this answer
1  
This assumes that there are no arguments between the end of options and --, i.e. script foo -- bar would pass foo -- bar to the external program. My answer doesn't make that assumption as it wasn't explicitly stated in the question. –  jw013 Nov 14 '12 at 23:05
    
Except where the OP says "I now want to remove the leading --" –  glenn jackman Nov 14 '12 at 23:21
    
That was for the example -- -d internalparams. In any case my answer is general enough to handle either case. –  jw013 Nov 14 '12 at 23:55
add comment

Use the built-in shift. First, do the normal getopts for your script. Once that loop completes,

shift "$((OPTIND - 1))"

will shift out all the already processed options.

From there, you'll have to finish processing the non-option arguments, if any, to the first part of the script (before the --). Once you encounter the --, shift it out until only the latter portion remains (the -d internalparam part that comes after --). One way to do this (using bash syntax):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Finally, only the second set of options / arguments remain, which you can pass on. Do NOT use $* to pass the remaining parameters to another command. Use "$@" instead, which preserves the original word splitting.

external_command "$@"
share|improve this answer
    
Yes, thanks! But how exactly do I find --? –  highsciguy Nov 14 '12 at 22:20
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.