According to the getopt man pages, for example: http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html If the first character (following any optional '+' or '-' described above) of optstring is a colon (':'), then getopt() returns ':' instead of '?' to indicate a missing option argument. However, the code in getopt.c does not consistently follow this rule. $ cat foo.c #include <unistd.h> #include <stdio.h> int main (int argc, char **argv) { int c = getopt (argc, argv, "+:a:b"); if (c == -1) puts ("got -1"); else printf ("got %c\n", c); c = getopt (argc, argv, "+:a:b"); if (c == -1) puts ("got -1"); else printf ("got %c\n", c); return 0; } $ ./foo -a ./foo2: option requires an argument -- a got : got -1 $ ./foo -b -a got b ./foo2: option requires an argument -- a got ? Expected behavior - stderr should be silent, and the -a without argument should return ':', not '?'. Workaround: code can set opterr=0 before the first getopt{,_long} call (to silence the spurious warning if argv[1] is missing an argument), then leave off the leading '-' or '+' of opstring for all subsequent calls for a given argc/argv parse (to silence the warning and return ':' instead of '?' if any subsequent argv is missing an argument).
Created attachment 4435 [details] patch 2009-12-01 Eric Blake <ebb9@byu.net> * posix/getopt.c (_getopt_internal_r): Skip optional - or + before checking lead byte of optstring for :.
Another related problem, which is also fixed by the previously posted patch: $ cat foo.c #include <unistd.h> #include <stdio.h> int main (int argc, char **argv) { int i, c; for (i = 0; i <= 1; i++) { optind = i; c = getopt (argc, argv, "+a"); if (c == -1) printf ("got -1, optind %d\n", optind); else printf ("got %c, optind %d\n", c, optind); } return 0; } $ ./foo -+ foo: invalid option -- '+' got ?, optind 2 got +, optind 2 Expected behavior is for the error message to occur twice on stderr, with both passes returning '?'.
Fixed in git.