commandline switches 

*Tags*: command line parameters

How to handle command swithes in scripts. Here are the examples from the simplest to the most powerful one.

single switch (or in sequential order) 

[ "x$1" = "x-l" ] && {
  log_url=T
  shift
  }
[ "x$1" = "x-t" ] && {
  file_title=$2
  shift 2
  }

optional command parameters 

[ ${1+T} ] || fhelp
mto=$1
shift
mfm=$1
shift
[ ${1+T} ] && { msg=$1; shift; }

more than one switch in arbitrary order 

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

Many switch, any order, with parameters 

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'.

Meaningful Symbols 

if [ "$1:+T" -a "$1" != "@"  ] ; then
  saved_name=$1
  shift
fi

documented on: 2004.07.10

cmd:getopt 

getopt typical usage 

 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

Compatibilities 

BSD's getopt doesn't have optional argument, and -o switch. The (only) way to set it straight is:

    set -- `getopt ptd: "$@"`

Notes 

  1. 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.
  1. 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!

getopt example: getopt-parse.bash 

#!/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

optional argument 

-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

Trying history 

Trying history, 2005.02.06 

Note 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 --

Trying history 

    $ 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

unknown -options vs. GNU getopt 

http://www.linux.ie/old-list/47158.html

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
..and rewrites them in a quoted canonical form:
'-a' '-b' '-c' 'argC' '--foo' '--spam' 'xyzzy' '--' 'file1' 'file2'
..according to a specification. in the example above, that

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'

unknown -options vs. GNU getopt 

..but there does not appear to be any way of doing this!?

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,

T

documented on: 2005.02.06

unknown -options vs. GNU getopt 

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.

getopt, What's the right way to use 

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

getopt, the right way to use 

>        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

getopt, the right way to use 

 $ 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!*\?

get the last parameter 

General 

This is expensive, but works for >= 0 args:

for last do :; done
fdest=$last
test 
last="$0"
for last do echo Last arg: "$last"; done
echo Last arg: "$last"; exit

Simple but limited 

This only works for 0-9 args:

eval fdest=\$$#

documented on: 2000.07.17 Mon 16:06:48

cmd:bash positional parameter 

*Tags*: cmd:set

Usage 

set positional parameters 
$ set a1 'b2 more' "c3 333" d4
use positional parameters 
 $ 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
clear positional parameters 
 $ set --

 $ echo $1
substitute with new set 
 set -- $files
 set -- `getopt "hp:s:" "$@"` || fhelp
 set x `date`
from command, with space 
 $ 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

Help 

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.

Comments 

   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 -.

How to pass switch/parameter pair 

Symptom 

confirm="-w 'Go on download it'"

can't be passed alone.

Solution / Conclusion 

confirm="Go on download it"
set -- ${confirm:+-w "$confirm"}
Tip !!
 $ echo $1
 -w

 $ echo $2
 Go on download it