[ "x$1" = "x-l" ] && { log_url=T shift }
*Tags*: command line parameters
How to handle command swithes in scripts. Here are the examples from the simplest to the most powerful one.
[ "x$1" = "x-l" ] && { log_url=T shift }
[ "x$1" = "x-t" ] && { file_title=$2 shift 2 }
[ ${1+T} ] || fhelp mto=$1 shift mfm=$1 shift [ ${1+T} ] && { msg=$1; shift; }
while :; do case "$1" in -s*) fl_sys=T ;; # system file listing -p*) shift; prefix="$1" ;; # for the beg'ing of filename -s*) shift; surfix="$1" ;; # for end of filename, bfr .tgz *) break ;; esac shift done
use getopt, but really suggest using the previous method for compatibility reasons.
set -- `getopt "clhstx" "$@"` || fhelp
while :; do case "$1" in -s) fl_sys=T ;; # system file listing -c) fl_csh=T ;; # csh/tcsh system file listing -p*) shift; prefix="$1" ;; # for the beg'ing of filename -t*) shift; surfix="$1" ;; # for end of filename, bfr .tgz --) shift; break ;; esac shift done
and can be called with combined switch such as '-sc..t'.
if [ "$1:+T" -a "$1" != "@" ] ; then saved_name=$1 shift fi
documented on: 2004.07.10
eval set -- `getopt -o ab:c:: -- "$@"` parameters '-a' does not require an argument. parameters '-b' requires an argument. parameters '-c' has an optional argument. while :; do case "$1" in -a) hour_enable=T ;; -b) shift; prefix="$1" ;; # prefix tag to add to the beg'ing of filename -c) shift; # c has an optional argument. As we are in quoted mode, # an empty parameter will be generated if its optional # argument is not found. case "$1" in "") echo "Option c, no argument";; *) echo "Option c, argument \`$1'";; esac;; --) shift; break ;; esac shift done
BSD's getopt doesn't have optional argument, and -o switch. The (only) way to set it straight is:
set -- `getopt ptd: "$@"`
Parameter '—' in getopt is mandatory. Otherwise:
set -- -t -p -d 20 'ps -eo $ eval set -- `getopt -o ptd:: "$@"` getopt: invalid option -- d Try `getopt --help' for more information.
eval is necessary. Otherwise will cause excessive quote:
# Normal: $ eval set -- `getopt -o ptd:: -- "$@"` ++ getopt -o ptd:: -- -d -t -p 20 'ps -eaf | sort' + eval set -- -d ''\'''\''' -t -p -- ''\''20'\''' ''\''ps' -eaf '|' 'sort'\''' ++ set -- -d '' -t -p -- 20 'ps -eaf | sort' # No eval, excessive quote: $ set -- `getopt -o ptd:: -- "$@"` ++ getopt -o ptd:: -- -d ''\'''\''' -t -p -- ''\''20'\''' ''\''ps' -eaf '|' 'sort'\''' + set -- -d ''\'''\''' -t -p -- ''\'''\''\'\'''\'''\''\'\'''\'''\''' ''\'''\''\'\'''\''20'\''\'\'''\'''\''' ''\'''\''\'\'''\''ps'\''' ''\''-eaf'\''' ''\''|'\''' ''\''sort'\''\'\'''\'''\'''
NB, for previous case, "set — `getopt ptd: "$@"`", word "eval" should not be used!
#!/bin/bash # A small example program for using the new getopt(1) program. # This program will only work with bash(1) # An similar program using the tcsh(1) script language can be found # as parse.tcsh # Example input and output (from the bash prompt): # ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " # Option a # Option c, no argument # Option c, argument `more' # Option b, argument ` very long ' # Remaining arguments: # --> `par1' # --> `another arg' # --> `wow!*\?' # Note that we use `"$@"' to let each command-line parameter expand to a # separate word. The quotes around `$@' are essential! # We need TEMP as the `eval set --' would nuke the return value of getopt. TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ -n 'example.bash' -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP" while true ; do case "$1" in -a|--a-long) echo "Option a" ; shift ;; -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; -c|--c-long) # c has an optional argument. As we are in quoted mode, # an empty parameter will be generated if its optional # argument is not found. case "$2" in "") echo "Option c, no argument"; shift 2 ;; *) echo "Option c, argument \`$2'" ; shift 2 ;; esac ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done echo "Remaining arguments:" for arg do echo '--> '"\`$arg'" ; done
-c|--c-long) # c has an optional argument. As we are in quoted mode, # an empty parameter will be generated if its optional # argument is not found. case "$2" in "") echo "Option c, no argument"; shift 2 ;; *) echo "Option c, argument \`$2'" ; shift 2 ;; esac ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;;
$ getopt-parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " Option a Option c, no argument Option c, argument `more' Option b, argument ` very long ' Remaining arguments: --> `par1' --> `another arg' --> `wow!*\?' $ getopt-parse.bash -a par1 'another arg' --c-long='wow!*\?' -cmore -b " very long " Option a Option c, argument `wow!*\?' Option c, argument `more' Option b, argument ` very long ' Remaining arguments: --> `par1' --> `another arg' $ getopt-parse.bash -m kj example.bash: invalid option -- m Terminating...
documented on: 2000.07.27 Thu 16:18:18
![]() |
if use -o, then need the — between options/optstring and parameters. |
$ getopt "abcd:" -abc -a -b -c -- $ getopt -abc -o "abcd:" getopt: invalid option -- b Try `getopt --help' for more information. $ getopt -o "abcd:" -- -abc -a -b -c --
$ set -x $ set -- -t -p -d 20 'ps -eo ' + set -- -t -p -d 20 'ps -eo ' $ echo "$@" + echo -t -p -d 20 'ps -eo ' -t -p -d 20 ps -eo $ set -- `getopt -o ptd: "$@"` ++ getopt -o ptd: -t -p -d 20 'ps -eo ' + set -- -- ptd: -t -p -d 20 ps -eo $ echo "$@" + echo -- ptd: -t -p -d 20 ps -eo -- ptd: -t -p -d 20 ps -eo $ set -- -t -p -d 20 'ps -eo ' + set -- -t -p -d 20 'ps -eo ' $ set -- `getopt ptd: "$@"` ++ getopt ptd: -t -p -d 20 'ps -eo ' + set -- -t -p -d 20 -- ps -eo $ echo "$@" + echo -t -p -d 20 -- ps -eo -t -p -d 20 -- ps -eo
I'm writing a wrapper shell script around less(1) for various bizarre reasons that are not particularly relevant, and in the process of doing so, also experimenting with GNU getopt(1), rather than the Bourne-ish shells's builtin getopts(1).
the issue is there's a handful of -short/—long-options my script handles, and everything else (options and filenames) is to be passed on to `less'. this is relatively easy to do with a hand-coded argument parser; slightly harder but AFAIK possible with the extended `getopts' builtinto the Korn and bash shells (but not the basic one in the System V Bourne shell); but does not seem possible at all with GNU `getopt'!?
roughly speaking, GNU `getopt' takes arguments, e.g.:
-a -bc argC --foo file1 --spam=xyzzy file2
'-a' '-b' '-c' 'argC' '--foo' '--spam' 'xyzzy' '--' 'file1' 'file2'
specification must have said `-a' and `-b' are valueless short options, `-c' is a short option which takes a value, `—foo' is a valueless long option, and `—spam' is a long option which takes a value:
unset GETOPT_COMPATIBLE POSIXLY_CORRECT getopt -o abc: -l foo,spam: ...
so far so good. however, if an unknown option-looking-arg (one which starts with a `-') is encountered, I cannot find any way of telling GNU `getopt' to treat it as just another string to position after the `—' in the rewritten form. e.g., if `—foo' in the above was *not* part of the spec, then I want `getopt' to rewrite the arguments to be:
'-a' '-b' '-c' 'argC' '--spam' 'xyzzy' '--' '--foo' 'file1' 'file2'
The trick is to set POSIXLY_CORRECT:
$ getopt -o abc: -l spam: -- -a -bc argC --spam=xyzzy file1 --foo file2 getopt: unrecognized option `--foo' -a -b -c 'argC' --spam 'xyzzy' -- 'file1' 'file2' $ POSIXLY_CORRECT=1 getopt -o abc: -l spam: -- -a -bc argC --spam=xyzzy file1 --foo file2 -a -b -c 'argC' --spam 'xyzzy' -- 'file1' '--foo' 'file2'
However, it is not perfect:
$ POSIXLY_CORRECT=1 getopt -o abc: -l spam: -- -a -bc argC --spam=xyzzy --foo file2 getopt: unrecognized option `--foo' -a -b -c 'argC' --spam 'xyzzy' -- 'file2'
I.e., there has to be a non-'-'-beginning string before —foo.
NB,
If the first character is `+', or if the environment variable POSIXLY_CORRECT is set, parsing stops as soon as the first non-option parameter (ie. a parameter that does not start with a '-') is found that is not an option argument. The remaining parameters are all interpreted as non-option parameters.
Each parameter not starting with a '-', and not a required argument of a previous option, is a non-option parameter. Each parameter after a '—' parameter is always interpreted as a non-option parameter. If the environment variable POSIXLY_CORRECT is set, or if the short option string started with a `+', all remaining parameters are interpreted as non-option parameters as soon as the first non-option parameter is found.
T
documented on: 2005.02.06
From getopt.c:
As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments.
Newsgroups: comp.os.linux.misc,comp.unix.shell Date: Thu, 13 Mar 2003 02:07:12 GMT
Thanks every one who replied, but the problem is that I'm writing a /bin/sh script. That's why I have to use getopt instead of getopts. The replies are either for bash or ksh. So, literately the problem is still not solved.
Does anyone have an answer to this? Thanks
> What's the right way to use getopt in shell scripts? > > In my script I have: > > fhelp(){ > # show help > exit > } > > set -- `getopt "ad:p:s:" "$@"` || fhelp > > But this doesn't catch the wrong options. My script just prompted > > getopt: invalid option -- x
T
> Example scripts for (ba)sh and (t)csh are provided with > the getopt(1) distribution, and are optionally installed > in /usr/local/lib/getopt or /usr/lib/getopt.
Example scripts are *optionally* installed, which are not included in any rpm distribution. Took me quite a while to find them…
http://www.kernel.org/pub/linux/utils/util-linux/ http://huizen.dds.nl/~frodol/getopt.html
Just for the archive. The answer is actually quite simple:
,----- | # We need TEMP as the `eval set --' would nuke the return value of getopt. | TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ | -n 'example.bash' -- "$@"` | | if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi | | eval set -- "$TEMP" `-----
T
$ set -- -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " $ echo "$@" -a par1 another arg --c-long wow!*\? -cmore -b very long $ eval set -- `getopt -o ab:c:: --long a-long,b-long:,c-long:: -n 'example.bash' -- "$@"` $ echo "$@" -a --c-long -c more -b very long -- par1 another arg wow!*\?
This is expensive, but works for >= 0 args:
for last do :; done fdest=$last
last="$0" for last do echo Last arg: "$last"; done echo Last arg: "$last"; exit
This only works for 0-9 args:
eval fdest=\$$#
documented on: 2000.07.17 Mon 16:06:48
*Tags*: cmd:set
$ set a1 'b2 more' "c3 333" d4
$ echo $1 a1 $ echo $2 b2 more $ echo $3 c3 333 $ for pp in "$@"; do echo $pp; done a1 b2 more c3 333 d4 $ for pp in "$*"; do echo $pp; done a1 b2 more c3 333 d4 $ for pp in $*; do echo $pp; done a1 b2 more c3 333 d4 set -- "$@" $ echo $2 b2 more
$ set -- $ echo $1
set -- $files set -- `getopt "hp:s:" "$@"` || fhelp set x `date`
$ ls -d S* SANS Intrusion Dectection.zip SONET - SDH Comp.rar [...] lst=`ls -d S*` set -- $lst $ echo $2 Intrusion lst=`ls -Qd S*` eval set -- $lst $ echo $2 SONET - SDH Comp.rar set -- $lst $ echo $1,$2 "SANS,Intrusion set a1 'b2 more' "c3 333" d4 eval set -- "$@" $lst $ echo $2 b2
Positional Parameters A positional parameter is a parameter denoted by one or more digits, other than the single digit 0. Positional parameters are assigned from the shell's arguments when it is invoked, and may be reassigned using the set builtin command.
set x `date` # Get the current day of the month into $4 set -- `getopt "hp:s:" "$@"` || fhelp
Q: Why to clear positional parameter before setting it?
A: — is for getopt, not set. 'set a1' then 'echo $2' will yield nothing.
Q: Why there sticked in an 'x' between set and `date`?
A: in case the date or getopt system calls fail, we won't get wrong returns from an empty set statement. Also, in case some of the positional parameters begin with a -.