Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 May 2000 11:36:04 -0400
From:      "Crist J. Clark" <cjc@cc942873-a.ewndsr1.nj.home.com>
To:        Mark Ovens <mark@dogma.freebsd-uk.eu.org>
Cc:        Erik Trulsson <ertr1013@student.csd.uu.se>, questions@freebsd.org
Subject:   Re: getopt(1) or getopts(1)?
Message-ID:  <20000514113604.A50543@cc942873-a.ewndsr1.nj.home.com>
In-Reply-To: <20000514110900.B232@parish>; from mark@dogma.freebsd-uk.eu.org on Sun, May 14, 2000 at 11:09:00AM %2B0100
References:  <20000511231319.C1522@parish> <20000512084656.A1146@student.csd.uu.se> <20000512183403.A233@parish> <20000513013931.C39310@cc942873-a.ewndsr1.nj.home.com> <20000514110900.B232@parish>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, May 14, 2000 at 11:09:00AM +0100, Mark Ovens wrote:
> On Sat, May 13, 2000 at 01:39:31AM -0400, Crist J. Clark wrote:
> > On Fri, May 12, 2000 at 06:34:03PM +0100, Mark Ovens wrote:
> > > On Fri, May 12, 2000 at 08:46:56AM +0200, Erik Trulsson wrote:
> > > > On Thu, May 11, 2000 at 11:13:19PM +0100, Mark Ovens wrote:
> > > > > Can someone clarify getopt(1) and getopts(1)? According to sh(1):
> > > > > 
> > > > >  getopts optstring var
> > > > >      The POSIX getopts command.  The getopts command deprecates the
> > > > >      older getopt(1) command.....
> > > > > 
> > > > > but there is no manpage for getopts(1), only getopt(1). The latter
> > > > > includes some sample code which works fine, however if I change
> > > > > ``getopt'' to ``getopts'' in this code I get:
> > > > > 
> > > > > parish:/usr/marko{89}% ./foobar -b
> > > > > getopts: -b: bad variable name
> > > > > Usage: ...
> > > > > parish:/usr/marko{90}%
> > > > > 
> > > > > Since getopt(1) is deprecated it would be better to use getopts(1).
> > > > > Can anyone explain the above error, or point me to some documentation
> > > > > for getopts(1)?
> > > > > 
> > > > 
> > > > On my system (4.0-stable) there is a manpage for getopts(1). It just a link
> > > > to buiiltin(1) which says that it is a builtin command in sh(1).
> > > 
> > > Same here (I'm also on 4-stable). I hadn't spotted that it is a copy
> > > of (not a link to) builtin(1).
> > 
> > It is a link, hardlink.
> > 
> >   % cd /usr/share/man/man1
> >   % ls -li getopts.1.gz builtin.1.gz getopt.1.gz 
> >   508294 -r--r--r--  71 root  wheel  2407 Mar 25 03:08 builtin.1.gz
> >   508336 -r--r--r--   1 root  wheel  1649 Mar 25 03:10 getopt.1.gz
> >   508294 -r--r--r--  71 root  wheel  2407 Mar 25 03:08 getopts.1.gz
> > 
> 
> Oops!
> 
> > 
> > > > The manpage for sh(1) has the following to say about getopts:
> > > > 
> > > >    getopts optstring var
> > > >           The POSIX getopts command.  The getopts command deprecates the
> > > >           older getopt(1) command.  The first argument should be a series
> > > >           of letters, each possibly followed by a colon which indicates
> > > >           that the option takes an argument.  The specified variable is set
> > > >           to the parsed option.  The index of the next argument is placed
> > > >           into the shell variable OPTIND. If an option takes an argument,
> > > >           it is placed into the shell variable OPTARG. If an invalid option
> > > >           is encountered, var is set to `?''. It returns a false value (1)
> > > >           when it encounters the end of the options.
> > > > 
> > > >
> > > 
> > > The first couple of lines of which I quoted in my original post so,
> > > yes, I have read it. However it reads as though the syntax is the same
> > > as getopt(1) (at least to me it does). So the question remains; why
> > > does the sample code in getopt(1) not work if I change ``getopt'' to
> > > ``getopts'' in the first line?
> > 
> > It really is nothing like getopt(1). Not sure where it says anything
> > there that would lead one to believe that.
> > 
> 
> Yes, when I read it slowly several times I realized that :)
> 
> > > I'm quite happy to RTFM, if only I could find a FM to R :)
> > 
> > But this is a very good point. I can't find the FM, but for some
> > reason, I know how to use this... It works more like getopt(3); maybe
> > that's why it feels familiar.
> > 
> > To get about the same functionality you see in the getopt(1) manpage,
> > you would have something like, 
> > 
> >   while getopts abo: OPT; do
> >       case $OPT in
> > 	  a|b)
> > 	      echo flag $OPT set; sflags="${OPT#-}$sflags"
> >               ;;
> > 	  o)
> > 	      echo oarg is "'"$OPTARG"'"; oarg="$OPTARG"
> >               ;;
> > 	  *)
> > 	      echo ERROR
> > 	      exit 2
> >       esac
> >   done
> >   echo single-char flags: "'"$sflags"'"
> >   echo oarg is "'"$oarg"'"
> > 
> > getopts cycles through the argument list on its own. No need to
> > shift. It places the current option (the single letter) in the var
> > specified. The argument of the option, if it takes one, is in
> > OPTARG. Your current position on the command line is stored in OPTIND
> > (and is started at the first argument if OPTIND is unset).
> > 
> 
> I'd almost got there, except I didn't know that shift wasn't needed.
> 
> > Almost makes life too easy, huh?
> 
> Almost. It does seem somewhat lacking in the error handling dept.
> though. Using the example code above, if you do:
> 
> 	# foobar -o -a -b
> 
> then getopts(1) thinks that ``-a'' is the argument to ``-o''.

How do you know it is not?

> Also, if it encounters an error such as an illegal option, or a
> missing argument then getopts(1) prints it's own error but sets $OPT
> to ``?'' which makes it difficult to generate your own error message,
> so instead of:
> 
>    # foobar -a -b -o
>    No arg for -o option
>    #
> 
> you could output "-o requires a valid path as an argument" which would
> be easy if $OPT was set to ``o'' as you could test for $OPTARG = "" in
> the o case. OK, you could probably do it by keeping track of $OPTIND,
> but that points to the *next* option and if the error occurs on the
> last option it is set to 1, so you need to track the previous value of
> $OPTIND.

Problem with your idea is that a null string could be valid input,

  $ foo -a -o ""

Second, you only can run out of options when the option requiring an
argument is the last command line argument. You can lookup what the
last one is pretty easily, `eval LAST=\$$#`.

Are you pointing out weaknesses in the whole "getopt(s)" concept or
complaining about getopts? getopt(1) has the same issues. getopts is
definately not for use in all situations and never will be.
-- 
Crist J. Clark                           cjclark@home.com


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000514113604.A50543>