8

I often find myself writing shell functions or shell scripts that are meant to be wrappers around other commands.

It is also frequent that I want such a wrapper to support a few flags/options. The idea is that the wrapper should cull from the command-line arguments all the flags/options it supports (along with their arguments, when applicable), and pass the remaining arguments as the arguments to the wrapped command.

Now, more often than not, the wrapped command also supports flags and options of its own. This means that, according to the scheme described above, the wrapper must be able to handle command-line arguments that include both its own flags/options as well as those supported by the wrapped command.

One way to implement such a wrapper would be to specify both the wrapper's and the wrapped command's options in a call to GNU getopt, then collect all the latter, together with any non-option arguments, in some array WRAPPED_COMMAND_ARGUMENTS. Then, at some later time, the wrapped command gets invoked with "${WRAPPED_COMMAND_ARGUMENTS[@]}" as its command-line arguments.

This approach has worked reasonably well for me, but it becomes prohibitively laborious when the wrapped command has a lot of options.

Instead, I would like to find what in this post's title I refer to as a "permissive alternative to GNU getopt." By this I mean a tool that, like getopt, helps me parse the options that I explicitly tell it about, and treats all the other remaining arguments equally, i.e. making no distinction based on the presence or not of leading hyphens.

Is there such a thing?

1
  • If C++ is an option there are many solutions - some even not requiring a 999GB lib.
    – Vorac
    Commented Jul 20, 2023 at 17:52

1 Answer 1

14

A common method for tasks like this is to use -- as a separator between options to be handled by the wrapper script and options to be passed on verbatim to the program being executed by the wrapper, e.g.

./my-wrapper -a -b -c -- -d -e -f

-- marks the end of options for my-wrapper. All other arguments, and all options after the -- can be passed on to the program it wraps, your wrapper script doesn't need to handle them at all.

It also allows for conflicting uses of options - e.g. grep and many other programs use -i to mean that searches should be case-insensitive, while you may want to use -i in your wrapper script to specify an input file. By using --, there's no conflict - -i before the -- means "input file", -i after the -- means "case insensitive".

Also worth noting: the program you wrap may also interpret -- as the end of its options, with everything after -- being treated as filenames or strings or other non-option arguments (e.g. to prevent filenames beginning with - being treated as options).

./my-wrapper -a -b -c -- -d -e -f -- non-option args here

BTW, -- has been used to mark the end of options since at least the late 1970s or early 1980s.

3
  • 3
    This was my first thought as well. Using -- plus a simple case statement that has a clause for each supported option makes this both easily readable, and relatively easy to maintain (and also far more portable than trying to use GNU getopt). Commented Jul 18, 2023 at 11:46
  • I'm not exactly sure what either you or the OP are referring to when you say "GNU getopt" - are you referring to getopt(3) in GNU libc? the getopts built-in in bash? or the getopt program from util-linux (which is GPL but not GNU)? None of them would have any problem dealing with --, in fact it's built in to libc's getopt function and util-linux's getopt command, and easy to match with bash's getopts. Easy with custom-written option processing too.
    – cas
    Commented Jul 18, 2023 at 15:37
  • Usually, getopt as present on a system with a GNU-derived userspace. In this case though, it doesn’t matter much, because despite being part of POSIX getopt is notoriously non-portable (largely because of the glibc routines deviating significantly by default and it not being possible to get 100% compliant behavior). Commented Jul 18, 2023 at 16:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .