Discussion:
[Help-bash] Bash script supporting complex options like GNU find
Peng Yu
2018-02-10 17:42:53 UTC
Permalink
Hi,

I currently use getopt to support -s --long like options in bash scripts.

https://github.com/karelzak/util-linux/blob/master/misc-utils/getopt-parse.bash

But this solution does not support complex expressions made of '-a'
'-o' '!' '(' and ')' as in defined in GNU find.

Does anybody know a solution that can make a bash script support these
complex expressions?
--
Regards,
Peng
Tim Visher
2018-02-12 13:34:34 UTC
Permalink
Post by Peng Yu
I currently use getopt to support -s --long like options in bash scripts.
https://github.com/karelzak/util-linux/blob/master/misc-
utils/getopt-parse.bash
But this solution does not support complex expressions made of '-a'
'-o' '!' '(' and ')' as in defined in GNU find.
Does anybody know a solution that can make a bash script support these
complex expressions?
Using a manual while loop is the most generic and powerful option.

https://mywiki.wooledge.org/BashFAQ/035

--

In Christ,

Timmy V.

https://blog.twonegatives.com
https://five.sentenc.es
Peng Yu
2018-02-12 14:46:39 UTC
Permalink
Post by Tim Visher
https://mywiki.wooledge.org/BashFAQ/035
The examples there cannot be readily extended to support '(' ')' '-a'
'-o' '!' as in GNU find. In fact, I doubt that getopt can support
them.

If you think otherwise, could you show an example how '(' ')' '-a'
'-o' '!' can be supported with getopt?
--
Regards,
Peng
Greg Wooledge
2018-02-12 14:52:30 UTC
Permalink
Post by Peng Yu
Post by Tim Visher
https://mywiki.wooledge.org/BashFAQ/035
The examples there cannot be readily extended to support '(' ')' '-a'
'-o' '!' as in GNU find. In fact, I doubt that getopt can support
them.
If you think otherwise, could you show an example how '(' ')' '-a'
'-o' '!' can be supported with getopt?
getopt(1) does not "support" anything. All it does is rewite combined
options like -abc as -a -b -c so that a simple while loop can more easily
parse them.

You will have to write your own syntax parsing for this.

getopt(1) is a really bad idea, and you should not be using it, regardless
of whether you also need to write an infix expression parser.
Eric Blake
2018-02-12 15:24:23 UTC
Permalink
Post by Peng Yu
Post by Tim Visher
https://mywiki.wooledge.org/BashFAQ/035
The examples there cannot be readily extended to support '(' ')' '-a'
'-o' '!' as in GNU find. In fact, I doubt that getopt can support
them.
If you think otherwise, could you show an example how '(' ')' '-a'
'-o' '!' can be supported with getopt?
If you need inspiration on how to write an option parser that matches
find(1), then read the source code for find [1] for inspiration. Note
that it does not use getopt() for parsing the bulk of its command line,
but its own hand-rolled parser. And therefore, any reimplementation
will likewise have to use custom manual parsing rather than being able
to rely on getopt-like libraries.

[1] https://git.savannah.gnu.org/cgit/findutils.git/tree/find/parser.c

But your goal of re-writing find(1) in shell seems rather quixotic.
You're investing a lot of time into something that will never compete in
speed with the native C version, so about the only benefit you will get
from your efforts is a better appreciation of how shell programming
works (or does not work), and not something that anyone else would ever
want to use.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
Greg Wooledge
2018-02-12 13:44:17 UTC
Permalink
Post by Peng Yu
I currently use getopt to support -s --long like options in bash scripts.
https://github.com/karelzak/util-linux/blob/master/misc-utils/getopt-parse.bash
I would not advise doing this.

Oh, you need *reasons*? OK, here's the top one: the getopt(1) software
you are using is a nonstandard GNU command which acts ENTIRELY DIFFERENTLY
from the getopt(1) command that is commonly present on Unix systems.
Anyone attempting to run your script on a Unix-that-is-not-GNU system
will encounter the (broken) traditional behavior. Not only will your
--long-options NOT work, but any argument containing a space, or any
empty argument, will just completely break.


From the HP-UX (11.11) getopt(1) man page:

WARNINGS
getopt option arguments must not be null strings nor contain embedded
blanks.


From the OpenBSD getopt(1) at <https://man.openbsd.org/getopt>:

CAVEATS
Note that the construction set -- `getopt optstring $*` is not
recommended, as the exit value from set will prevent the exit value
from getopt from being determined.

BUGS
Whatever getopt(3) has.

Arguments containing whitespace or embedded shell metacharacters
generally will not survive intact; this looks easy to fix but isn't.

The error message for an invalid option is identified as coming from
getopt rather than from the shell procedure containing the invocation
of getopt; this again is hard to fix.

The precise best way to use the set command to set the arguments without
disrupting the value(s) of shell options varies from one shell version
to another.
Post by Peng Yu
But this solution does not support complex expressions made of '-a'
'-o' '!' '(' and ')' as in defined in GNU find.
Does anybody know a solution that can make a bash script support these
complex expressions?
Yes: write your own option processing code.

Here's another general tidbit of advice: if you find yourself wondering
how to construct an abstract syntax tree in a bash script, you probably
shouldn't be writing this project in bash.
Loading...