> https://docs.python.org/3/library/argparse.html is great Argparse is okay (and being in stdlib makes it always-available), but it's no click. https://click.palletsprojects.com/en/7.x/
Thumbs up for 'Click'. I used it for a project once, and I was really happy with it. Easy to use, good docs. Would use it again.
Googling the library appears to be about ~8,000 lines of code (core.py is ~2,000 alone).
Is that really reasonable sounding to most people for parsing CLI input/output and display manpages or helptext?
I like the idea of combining the header with the help documentation to reduce the number of areas to maintain in smaller scripts. For larger scripts though, I think I'd still prefer to have a separate function, so that the help documentation doesn't overwhelm the initial viewing of the actual code. I also like to feed a heredoc directly into man, which allows you to achieve nicer formatting for the help documentation…
Note that this doesn't work on macOS, where the builtin `man` command doesn't support the `-l` option.
Ah interesting, is there any workaround for Mac? Otherwise, I may just have to fallback to stripping the man page formatting and sending it to less.
You can also use a "here document" help() { cat Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH } If the indentation bugs you, you can use a simpler sed trick to remove leading space so that you can indent it as desired: help() { sed -e 's/ //' Options: Input file to read. Output file to write. Use '-' for stdout. -h Show this message. EOH }
The neat thing about not indenting it is that you can make use of your editor's text-width auto-wrapping. For example, if you have it set to 80 columns, indenting it would make the text-width of the help text 76 in your case.
Also, putting the help text in code like this instead of a comment allows one to expand $0 so that the command name in the help text always matches the filename and path used in the invocation.
This seems like a neat sed trick, but I'm not sure that it's useful for this particular case? When I write a shell script, I often write a help function if it's not a totally trivial script, but there's no need for this cryptic sed expression, right? You can just call `echo` a few times and do it the obvious way. That works better for maintainability and if you put it at the top of the file then it's immediately visi…
It's a little sad that standard shell here documents only support elliding leading tabs (it wouldn't be so sad if the record separator hadn't been thrown under the bus - having a character for indentation distinct from space is good... In theory). But at any rate my typical usage() is generally along these lines (warning watch out for expansions): usage() { cat - [-o|--optional-param] Etc. Possibly referencing defaul…
I think it'd be better without using basename, just $0. That way it matches the way it was called, which is how the user chose to access it for whatever reason. The bare filename might refer to a different command, even. Also, if you include examples in the help text, they'll also be able to copy and paste, instead of having to manually insert what basename stripped away.
Handling of arguments is one of the reasons I reach for Python or Powershell instead of a bash script when writing my own stuff. https://docs.python.org/3/library/argparse.html is great. Powershell has the Param keyword that functions like argparse in Python https://docs.microsoft.com/en-us/powershell/module/microsoft...
But handling args isn't that bad in bash. while [[ $# -gt 0 ]]; do case "$1" in -h|--help) do_help exit ;; -v|--version) do_version exit ;; -d|--debug) debug=true shift ;; -a|--arg) arg_value=$2 shift 2 ;; esac done
To expand on that pattern:
while (( $# )); do
case "$1" in
-h|--help)
usage
exit
;;
-v|--version)
do_version
exit
;;
-d|--debug)
debug=true
;;
-a|--arg)
arg_value="$2"
shift
;;
*)
if [[ ! -v pos1 ]]; then
pos1="$1"
elif [[ ! -v pos2 ]]; then
pos2="$1"
else
>&2 printf "%s: unrecognized argument\n" "$1"
>&2 usage
exit 1
fi
esac
shift
done
I also posted to the github gist, this the sed command here is not cross-plataform friendly. You can accomplish the same thing with an awk command though: awk '/^###/' "$0"
It's a little sad that standard shell here documents only support elliding leading tabs (it wouldn't be so sad if the record separator hadn't been thrown under the bus - having a character for indentation distinct from space is good... In theory). But at any rate my typical usage() is generally along these lines (warning watch out for expansions): usage() { cat - [-o|--optional-param] Etc. Possibly referencing defaul…
I think it'd be better without using basename, just $0. That way it matches the way it was called, which is how the user chose to access it for whatever reason. The bare filename might refer to a different command, even. Also, if you include examples in the help text, they'll also be able to copy and paste, instead of having to manually insert what basename stripped away.
True enough - I find it depends a bit on the nature of the script - if it's something buried under misc/tools/extra/bin/util.sh - i tend to prefer brevity - especially in the first paragraph/usage section (util.sh [optional param]).
But for more concrete examples I'll often leave off the basename - for easier cut and paste.