dash.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* getopts doesn't properly update OPTIND when called from function
@ 2015-05-28 18:54 Martijn Dekker
  2015-05-28 22:39 ` Harald van Dijk
  0 siblings, 1 reply; 9+ messages in thread
From: Martijn Dekker @ 2015-05-28 18:54 UTC (permalink / raw)
  To: dash

I'm writing a shell function that extends the functionality of the
'getopts' builtin. For that to work, it is necessary to call the
'getopts' builtin from the shell function.

The POSIX standard specifies that OPTIND and OPTARG are global
variables, even though the positional parameters are local to the
function.[*] This makes it possible to call 'getopts' from a function by
simply passing the global positional parameters along by adding "$@".

My problem is that dash does not properly update the global OPTIND
variable when getopts is called from a function, which defeats my
function on dash. It updates the global OPTIND for the first option but
not for subsequent options, so OPTIND gets stuck on 3. (It does
accurately update the global OPTARG variable, though.)

I made a little test program that demonstrates this; see below the
footnote. It succeeds on bash, ksh93, pdksh, mksh, and yash, but not
(d)ash or zsh[*2].

The output of my test script seems consistent with the hypothesis that
OPTIND is reinitialized to 1 whenever a function is called. It should
only be initialized when the shell is initialized.

I suspect this is an old bug as other versions of ash, including Busybox
ash and NetBSD's /bin/sh, share it.

Thanks,

- Martijn

[*] The POSIX standard specifies:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html
"The shell variable specified by the name operand, OPTIND, and OPTARG
shall affect the current shell execution environment", which implies
that they are global variables.
    Confusingly, that same page also says: "The shell variables OPTIND
and OPTARG shall be local to the caller of getopts and shall not be
exported by default."
    But I believe that "caller" here means the program that calls
getopts, not the function; POSIX does not support function-local
variables. This interpretation is supported by the added phrase "... and
shall not be exported by default" and by the evidence that the majority
of popular shells pass my test script. Also, it is in fact global in
dash; after all, it does get updated just once...
    (Of course it should be possible to explicitly make OPTIND and
OPTARG local using the non-standard 'local' keyword.)

[*2] In zsh, OPTIND appears to be local to the function as the
positional parameters are, so in my test script OPTIND is stuck at 1. I
submitted a bug report to zsh-workers and a patch was posted in less
than an hour!

#### begin test script ####

#! /bin/sh

expect() {
    if [ "X$2" = "X$3" ]; then
        printf '%s: OK, got "%s"\n' "$1" "$2"
    else
        printf '%s: BUG: expected "%s", got "%s"\n' "$1" "$2" "$3"
        return 1
    fi
}

callgetopts() {
    getopts 'D:ln:vhL' opt "$@"
}

testfn() {
    expect OPTIND 1 "$OPTIND"

    callgetopts "$@"
    expect opt D "$opt"
    expect OPTARG 'test' "$OPTARG"

    callgetopts "$@"
    expect opt h "$opt"
    expect OPTARG '' "$OPTARG"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"
    expect opt n "$opt"
    expect OPTARG 1 "$OPTARG"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"
}

testfn -D test -hn 1 test arguments

#### end test script ####

Output on dash 0.5.6 and current dash git version:

OPTIND: OK, got "1"
opt: OK, got "D"
OPTARG: OK, got "test"
opt: BUG: expected "h", got "D"
OPTARG: BUG: expected "", got "test"
OPTIND: BUG: expected "5", got "3"
opt: BUG: expected "n", got "D"
OPTARG: BUG: expected "1", got "test"
OPTIND: BUG: expected "5", got "3"
OPTIND: BUG: expected "5", got "3"

Expected output (on bash, *ksh*, yash):

OPTIND: OK, got "1"
opt: OK, got "D"
OPTARG: OK, got "test"
opt: OK, got "h"
OPTARG: OK, got ""
OPTIND: OK, got "5"
opt: OK, got "n"
OPTARG: OK, got "1"
OPTIND: OK, got "5"
OPTIND: OK, got "5"

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-06-04 19:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-28 18:54 getopts doesn't properly update OPTIND when called from function Martijn Dekker
2015-05-28 22:39 ` Harald van Dijk
2015-05-29  2:58   ` Herbert Xu
2015-05-29  5:50     ` Harald van Dijk
2015-06-01  6:29       ` Herbert Xu
2015-06-01 17:30         ` Harald van Dijk
2015-06-01 22:10           ` Jilles Tjoelker
2015-06-02  0:21             ` Harald van Dijk
2015-06-04 19:56   ` Martijn Dekker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).