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

The bash getopts builtin does not support long option names with the double-dash prefix. It only supports single-character options.

The bash getopts builtin does not support long option names with the double-dash prefix. It only supports single-character options. There is a shell tool getopt which is another program, not a bash builtin.

The GNU implementation of getopt (e.g. On Linux) supports parsing long options. But the BSD implementation of getopt (e.g. On Mac OS X) does not.

D – Jonathan Leffler Dec 31 '08 at 6:29 3 Great minds think alike! – Bill Karwin Dec 31 '08 at 6:31 1 Use getopts folks, not getopt. Bash-hackers.

Org/wiki/doku. Php/howto/getopts_tutorial – hendry Aug 20 '09 at 23:22 4 @hendry: Can you explain why you say that? Even that article you link to has a prominent notice that getopts doesn't support long option names as the OP asks for.

– Bill Karwin Aug 20 '09 at 23:32 3 GNU Getopt seems to be the only choice. On Mac, install GNU getopt from macports. On Windows, I'd install GNU getopt with Cygwin.

– Bill Karwin Oct 18 '09 at 4:23.

The built-in getopts command is still, AFAIK, limited to single-character options only. There is (or used to be) an external program getopt that would reorganize a set of options such that it was easier to parse. You could adapt that design to handle long options too.

Example usage: aflag=no bflag=no flist="" set -- $(getopt abf: "$@") while $# -gt 0 do case "$1" in (-a) aflag=yes;; (-b) bflag=yes;; (-f) flist="$flist $2"; shift;; (--) shift; break;; (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; (*) break;; esac shift done # Process remaining non-option arguments ... You could use a similar scheme with a getoptlong command.

1 +1 for small example – Leonel Aug 10 '09 at 18:55 2 getopt, except for the GNU version (which has a different calling convention), is fundamentally broken. Do not use it. Please use **getopts instead bash-hackers.Org/wiki/doku.

Php/howto/getopts_tutorial – hendry Aug 20 '09 at 23:21 +1 great example – Tom Auger Jul 18 at 19:31 @hendry - from your own link: "Note that getopts is not able to parse GNU-style long options (--myoption) or XF86-style long options (-myoption)! " – Tom Auger Jul 18 at 19:32.

Getopt and getopts become very frustrating to use, especially when one has many flags. Keeping the list of options in sync with the case statement used is one thing, but if you need to update a 'usage' function which outputs a listing of all the flags, you easily forget to document your flags. Take a look at shFlags code.google.com/p/shflags/ which is a portable shell library (meaning sh, bash, dash, ksh, zsh on Linux, Solaris, etc.).

I wrote to wrap getopt to make the whole process easier. It makes adding new flags as simple as adding one line to your script, and it provides an auto generated usage function. Here is a simple ' world!

' using shFlags. #! /bin/sh # source shflags from current directory .

. /shflags # define a 'name' command-line string flag DEFINE_string 'name' 'world' 'name to say hello to' 'n' # parse the command-line FLAGS "$@" || exit 1 eval set -- "${FLAGS_ARGV}" # say hello echo " ${FLAGS_name}!" For OSes that have the enhanced getopt that supports long options (e.g. Linux), you can do: $ .

/hello_world. Sh --name Kate Kate! For the rest, you must use the short option: $ .

/hello_world. Sh -n Kate Kate! Adding a new flag is as simple as adding a new DEFINE_ call.

Kate.

This is great! I will use it – Janning Jan 26 at 8:18 This is fantastic but unfortunately my getopt (OS X) doesn't support spaces in arguments :/ wonder if there is an alternative. – Alastair Stuart Mar 16 at 16:16 +1 nice one .... – Felipe Alvarez Apr 8 at 0:27.

The built-in getopts can't do this. There is an external getopt(1) program that can do this, but you only get it on Linux from the util-linux package. It comes with an example script getopt-parse.bash.

There is also a getopts_long written as a shell function.

! /bin/bash while getopts "abc:d:" flag do case $flag in a) echo "getopts:$OPTIND==> -$flag";; b) echo "getopts:$OPTIND==> -$flag";; c) echo "getopts:$OPTIND==> -$flag $OPTARG";; d) echo "getopts:$OPTIND==> -$flag $OPTARG";; esac done shift $((OPTIND-1)) echo "otheropts==> $@" exit . #!

/bin/bash until -z "$1" ; do case $1 in "--dlong") shift if "${1:1:0}"! = "-" then echo "==> dlong $1" shift fi;; *) echo "==> other $1"; shift;; esac done exit.

Usage ;; :) echo "option -$OPTARG requires an argument" usage ;; esac done.

Here's an example that actually uses getopt with long options: aflag=no bflag=no if! Options=$(getopt -o ab -l along,blong -- "$@") then # something went wrong, getopt will put out an error message for us exit 1 fi set -- $options while $# -gt 0 do case $1 in -a|--along) aflag="yes" ;; -b|--blong) bflag="yes" ;; (--) shift; break;; (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;; (*) break;; esac shift done.

1 for the long option example and conditional check of getopt return value. – Jason McCreary Dec 9 at 18:57.

1 This seems to work for me, I don't know what the problem is with this method, but it seems simple, so there must be a reason everyone else is not using it. – Billy Moon Aug 7 at 10:46 2 Wow it works so marvelously! – Theodore R.

Smith Aug 18 at 14:33 1 @Billy Yes, this is simple because I don't use any script to manage my parameters and etc. Basically I convert the arguments string ($@) to an array and I loop through it. In the loop, current value will be the key and the next one will be the value. Simple as that.

– Rafael Rinaldi Aug 23 at 23:23 1 @Theodore I'm glad this was helpful to you! It was a pain to me as well. If you're interested, you can see an example of it in action here: raw.github.

Com/rafaelrinaldi/swf-to-html/master/swf-to-html. Sh – Rafael Rinaldi Aug 23 at 23:24.

Getopts does support long names... while getopts "f(file):s(server):" flag do echo "$flag" $OPTIND $OPTARG done Or so the tutorials I have found have said. Try it and see.

My bash 4.1. 5 man page says nothing like that. – glenn jackman Jan 8 at 0:47 How to use? I cannot prove that long options are supported ...? – Felipe Alvarez Oct 6 at 2:59 This is ksh93's getopts builtin.

Apart from this syntax, it also has a more complicated syntax that also allows long options without a short equivalent, and more. – jilles Oct 9 at 12:28.

I have been working on that subject for quite a long time... and made my own library which you will need to source in your main script. See libopt4shell and cd2mpc for an example. Hope it helps!

The Bash builtin getopts function can be used to parse long options by putting a dash character followed by a colon into the optspec: #! /bin/bash optspec=":hv-:" while getopts "$optspec" optchar; do case "${optchar}" in -) case "${OPTARG}" in loglevel) val="${! OPTIND}"; OPTIND=$(( $OPTIND + 1 )) echo "Parsing option: '--${OPTARG}', value: '${val}'" >&2; ;; loglevel=*) val=${OPTARG#*=} opt=${OPTARG%=$val} echo "Parsing option: '--${opt}', value: '${val}'" >&2 ;; *) if "$OPTERR" = 1 && "${optspec:0:1}"!

= ":" ; then echo "Unknown option --${OPTARG}" >&2 fi ;; esac;; v) echo "Parsing option: '-${optchar}'" >&2 ;; *) if "$OPTERR"! = 1 || "${optspec:0:1}" = ":" ; then echo "Non-option argument: '-${OPTARG}'" >&2 fi ;; h) echo "usage: $0 -v --loglevel=" >&2 exit 2 ;; esac done Obviously getopts neither performs OPTERR checking nor option-argument parsing for the long options. The script fragement shows how this may be done manually.

The basic principle also works in the Debian Almquist shell ("dash"). Note the special case: getopts -- "-:" ## without the option terminator "-- " bash complains about "-:" getopts "-:" ## this works in the Debian Almquist shell ("dash") Note that, as GreyCat from over at http://mywiki.wooledge.org/BashFAQ points out, this trick exploits a non-standard behaviour of the shell which permits the option-argument (i.e. The filename in "-f filename") to be concatenated to the option (as in "-ffilename").

The POSIX standard says there must be a space between them, which in the case of "-- longoption" would terminate the option-parsing and turn all longoptions into non-option arguments.

People seem to have a bit of misunderstanding of what getopt and getopts do. They don't actually process your options for you, the way that e.g. The Getopt module in Perl or optparse/argparse modules in Python do. All that they do is canonicalize the options that are passed in -- i.e.

Convert them to a more standard form, so that it's easier for a shell script to process them. For example, an application of getopt might convert the following: myscript -ab -ooutfile. Txt infile.

Txt into this: myscript -a -b -o outfile. Txt infile. Txt You have to do the actual processing yourself.

You don't have to use getopt at all if you make the restriction on your program that you can only put one option per argument, and for options with values (e.g. -o above), the value has to go as a separate argument (after a space). For example, the following is an example of bog-standard option-processing, not using getopt, from a script of mine: VERBOSE=false DEBUG=false MEMORY= JAVA_MISC_OPT= while true; do case "$1" in -v | --verbose ) VERBOSE=true; shift ;; -d | --debug ) DEBUG=true; shift ;; -m | --memory ) MEMORY="$2"; shift 2 ;; --minheap ) JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;; --maxheap ) JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;; --escape-analysis ) JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:+DoEscapeAnalysis"; shift ;; --compressed-oops ) JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:+UseCompressedOops"; shift ;; -- ) shift; break ;; * ) break ;; esac done This lets you specify options like -m 4096 --minheap 20 --maxheap 40 --verbose or similar. The quoting around "$1" and such is important as it ensures that arguments with spaces in them get handled properly.

Say you wanted to getopt-ize the above using GNU getopt (which is part of Linux, and can be installed on Mac OS X by installing MacPorts followed by sudo port install getopt). Also say that our script is called javawrap. You'd then add the following code above the code just given: TEMP=`getopt -o vdm: --long verbose,debug,memory:,minheap:,escape-analysis,compressed-oops -n 'javawrap' -- ${1+"$@"}` if $?!

= 0 ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! Eval set -- "$TEMP" The effect of adding the above code is that If unrecognized options are given, an error will be output (that's why we need to pass in the name of our script, so the error will show our script name). Options and non-options can be mixed, rather than having to put all options first.

Shorter but non-ambiguous versions of long options are allowed, e.g. --escape-anal instead of --escape-analysis. You can specify long options using either the --minheap 20 or --minheap=20 style. If you add the -a flag to getopt, you can also specify long options using a single dash (Java-style, as in -minheap 20).

Short options can be combined into a single argument, e.g. -vd. Possibly other nice features. But note that all of these added features are optional, and you can get by perfectly well without them; you just have to use a more standard syntax when specifying the options.

Note that when you use the added code to call getopt, only the first line needs to be changed, and only the parts that specify short and long options, and specify your program name.(Basically, after -o you list your short options, with a colon after those that take values; after --long you list your long options separated by commas, again with a colon after those that take values; after -n, you give your program name.) All the rest is "boilerplate" code that should stay as-is. Also note that the above boilerplate is only for GNU getopt. If you use BSD getopt (i.e.

The one that's built in to Mac OS X or FreeBSD), you first of all can only tell it to parse short options, and second of all you need different boilerplate. Basically, BSD getopt is broken in numerous ways: First, that it can't handle long options, and second that it doesn't correctly handle spaces in command arguments. GNU getopt does both things correctly, but the result is that the boilerplate needs to be different (in particular, you need to say eval set instead of just set).

Sudo port install getopt #external program on Mac OS X.

" in $OPTARG, or disable long options after "--" in option fields. For ((i=1;$#;i++)) ; do case "$1" in --) # ${args$((i-1))} == ... || EndOpt=1 ;;& # DIRTY: we still can handle some execptions... EndOpt=1 ;;& --version) ((EndOpt)) && args$i="$1" || args$i="-V";; # default case : short option use the first char of the long option: --? *) ((EndOpt)) && args$i="$1" || args$i="-${1:2:1}";; # pass through anything else: *) args$i="$1" ;; esac shift done # reset the translated args set -- "${args@}" function usage { echo "Usage: $0 options files" >&2 exit $1 } # now we can process with getopt while getopts ":hvVc:" opt; do case $opt in h) usage ;; v) VERBOSE=true ;; V) echo $Version ; exit ;; c) source $OPTARG ;; \?

) echo "unrecognized option: -$opt" ; usage -1 ;; :) echo "option -$OPTARG requires an argument" usage -1 ;; esac done shift $((OPTIND-1)) "$1" == "--" && shift.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions