matejak / argbash Goto Github PK
View Code? Open in Web Editor NEWBash argument parsing code generator
License: Other
Bash argument parsing code generator
License: Other
$script_dir
should be defined after resolving the real path of the script, because the script could be used through a symlink.
Like this:
script_dir="$(cd "$(dirname $(realpath "${BASH_SOURCE[0]}"))" && pwd)" || die "Couldn't determine the script's running directory, which probably matters, bailing out" 2
Some arguments can have long descriptive names s.a. --add-another-value
, so it can be convenient to add a long, but abbreviated option (i.e. alias) s.a. --aavalue
.
I was wondering if argbash has any future plans to have parity with http://docopt.org/ in terms of help and usage formatting (not necessarily API/templating), provided that docopt is POSIX-compliant?
Right now, docopt has python dependencies, and has no pure bash implementation.
I would like to see please an example with the following type of options, where the short bool options (flags) can be combined into a single option:
Simple:
$ tar -xvzf tarfile.tar.gz
Where the options -x
, -v
, -z
, -f
are combined.
Slightly more complex:
$ tar -rv -f abc.tar abc.txt
Flags combined + case sensitive argument (-C
) + positional (filename "abc.tar.gz"):
$ tar -xvzf abc.tar.gz -C /opt/folder/
Examples from: http://www.binarytides.com/linux-tar-command/
At the moment, I'm not sure how much support argbash templates and API have for these flags.
The following directive doesn't work as expected:
# ARG_OPTIONAL_SINGLE([foo],[],[bar "bar2 bar3". bar4.])
The printf
command gets confused, as it gets multiple strings, instead of one with escaped quotes.
I'm trying to generate the following type of usage template:
Usage: my_program <host> <port>
So far, I've realized I can't use ARG_POSITIONAL_SINGLE
twice in a row as it throws an error.
And using the following template:
# ARG_POSITIONAL_MULTI([host][port],[Your host][Your port],2,[hosts][port])
# ARG_HELP([short program description (optional)], [long program description (optional)])
# ARGBASH_GO()
generates the help message:
short program description (optional)
Usage: script [-h|--help] <hostport-1> [<hostport-2>]
<hostport>: Your hostYour port (defaults for <hostport-2>: 'hostsport')
-h,--help: Prints help
long program description (optional)
Although they are technically repeated arguments with a max number of 2 repeats, I would like to know if it's possible to customize the template so that it generates my desired output.
Would really appreciate any guidance here. Thanks!
In the 2nd Argument to ARG_HELP it might be helpfull to embed newlines to create paragraphs in the help text at the end of the help message. In the current version these are printed as backslahs+n ("\n") instead of starting a new line.
A few minor proposals that would smooth out argbash
integration as described in #1. Didn't want to spam x issues and it's all a bit related.
I want to avoid duplicate static text as much as possible in my argbash
templates.
Use case:
Contextual help setup as described in the linked issue. Currently every "subparser" has to duplicate some static app header text in it's help message. On changes I need to touch potentially many files.
Proposal:
Add something like ARG_HELP_HEADER(["some header text"])
that, if defined, would display it's text before ARG_HELP
, this could then be defined once and included via ARGBASH_WRAP
in multiple scripts with different ARG_HELP
texts.
Edit: On second thought, I guess I could just define a _app_help_header="my app (c) foo"
variable in the main script and use ARG_HELP(["${_app_help_header} - command help"])
in the sourced templates?
EditEdit: ARG_HELP_FOOTER
or the ability to disable the argument validation in the generated code, so I could print some further text after the generated help, would also be very helpful. For example displaying the available commands in the main script.
For certain scripts I may need to override if print_help; exit 0
is called when --help
is passed to the script.
Use case:
Contextual help setup as described in the linked issue. The main script that wraps the "subparsers" should not display it's help text if --help
was intended for a valid sub-command, i.e. ./main.sh some-valid-cmd --help
Proposal:
Make automatic display of the help text in the generated parsing code configurable via template. When the auto-display is disabled the generated parsing code should instead define a variable like $_arg_help
which would enable handling of the help display by the script itself.
I want to configure the error messages related to argument parsing, mainly for too few/many arguments, per template. Currently it always displays FATAL ERROR: Not enough positional arguments - we require at least 1, but got only 0.
for too few arguments. New users that may not be very familiar with bash are probably gonna be confused what a positional argument could refer to. For example Error: Expected a filename - we require at least 1, but got only 0.
would most likely be much clearer for most people.
Use case:
Every script.
Proposal:
Make error message configurable. Maybe a configurable error prefix might be enough?
For a contextual help setup I need to modify the script prefix in the help display.
Use case:
Contextual help setup as described in the linked issue. Example:
$ ./main.sh some-cmd --help
This is the help text of some-cmd!
Usage: ./main.sh [--(no-)no-deps]
The displayed help is the help text of a sourced sub command template. Ideally it would display Usage: ./main.sh some-cmd ....
Proposal:
Add something like ARG_HELP_USAGE_SCRIPT_ARG_PREFIX(["some-cmd"])
that would then be inserted in the help text usage line.
With these resolved argbash
could be used to completly handle the parsing for a variety of constructs in a clean and elegant way. Thanks for this neat project!
It would be nice to have support for typo detection/suggestion, so e.g.
script --hepl
would produce a --hepl is an invalid argument, did you mean --help?
message
Invoking a script generated by argbash
with -e set (either with set -e
at the top or running it with bash -e
) will make handle_passed_args_count
fail silently with error code 1, since I guess the test
command actually fails by design (returns 1) if all the correct arguments are supplied.
Could it be possible to wrap scripts which are already wrapping other scripts?
It doesn't seem to work for the moment.
All my arguments are mandatory. I am confused about how to specify mandatory options so that I don't have to write logic to check all my args are passed.
Hi,
I'm often using the ARG_OPTIONAL_REPEATED macro with a default value being a variable.
For example:
# ARG_OPTIONAL_REPEATED([test],[t],[this is a test],["${my_array[@]}"])
I put the quotes around my array in order to preserve spaces in its values.
Hence, the _arg_test
variable is well set but in the help message, quotes are escaped, resulting in a weird display of my default values with quotes around as if they were only one long string.
Have you any idea how to deal with that ?
Following minimal reproducer:
$ cat invalid_group_var.m4
#!/bin/bash
# m4_ignore(
echo "This is just a script template, not the script (yet) - pass it to 'argbash' to fix this." >&2
exit 11 #)Created by argbash-init v2.4.1a
# ARG_HELP([<The general help message of my script>])
# ARG_OPTIONAL_REPEATED([long-option])
# ARG_TYPE_GROUP_SET([MYGROUP], [GROUP-TYPE], [long-option], [ foo,bar ])
# ARGBASH_GO
# [ <-- needed because of Argbash
echo "Value of --foo: ${_arg_long_option[@]}"
# ] <-- needed because of Argbash
$ argbash -o invalid_group_var.sh invalid_group_var.m4
Ran with bash:
$ bash invalid_group_var.sh --long-option foo --long-option bar
invalid_group_var.sh: line 88: _arg_long_option__long-option_SUFFIX=foo: command not found
Value of --foo: foo bar
produces error ^.
Relevant line is 78:
$ nl invalid_group_var.sh | tail -n 10
77 _arg_long_option="$(MYGROUP "$_arg_long_option" "long-option")" || exit 1
78 _arg_long_option__long-option_SUFFIX="$(MYGROUP "$_arg_long_option" "long-option" idx)"
79 ### END OF CODE GENERATED BY Argbash (sortof) ### ])
80 # [ <-- needed because of Argbash
81 echo "Value of --foo: ${_arg_long_option[@]}"
82 # ] <-- needed because of Argbash
I'm running the code with latest updates of Red Hat Enterprise Linux 7.4:
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ m4 --version
m4 (GNU M4) 1.4.16
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Rene' Seindal.
The code
# ARG_OPTIONAL_SINGLE([foo], f)
# ARG_OPTIONAL_SINGLE([bar], f)
# ARGBASH_GO()
doesn't produce the The short option 'f (in definition of '--bar') is already used
error.
Sometimes, I would like to use true
and false
for boolean flag values. For example, some of the flags
would make their way into go programs. argbash uses on
and off
as keywords to mean a flag is set or unset
Sadly these values are not immediately acceptable to say go programs -- though go acceps a number of different values, see here for details:
https://golang.org/pkg/flag/#pkg-overview
So I end up having a function to convert off
and on
into appropriate flags. Any chance that argbash could have a generation option to configure these values?
The reason I report this to argbash instead of just rolling my own scripting is because, in general, I want to minimize the amount of arcane bash that I need to write. If I could delegate part of this to an automated code generator, I'd be a happier camper.
Cheers!
Argbash could support a manpage generator of some form.
Easy: rst2man
or similar (this one is even easy to extend via a template provided by a user).
Difficult: Produce ready-to-install manpages that somehow also contain stuff that should be in the man page and can't be inferred from the command-line interface.
Would an option to support the generation of POSIX-compliant shell code be too much? Genuinely asking because I'm curious and trying to gauge interest.
The GNU standard allows abbreviations, so e.g. if a script supports a --foobar
argument and no other argument beginning by --foo...
, one can specify --foo
instead (presumably --foob
should do the trick too).
Source: https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
Hi,
Just letting you know of some installation pains and some blockers.
mac OSX High Sierra + homebrew and the latest commit: a585507
running "sudo make install PREFIX=/usr" as example says caused a mkdir -p ///usr/bin to be executed. So inside the Make file I see that ROOT is set to / already so no need to include a slash between the
"sudo make install PREFIX=usr/local"
Then after running arbash-init to create my template and attempting to "feed it back to argbash" I also get permission denied as follows:
BASHdan@ShuPro /Users/dan/bin/bash >>argbash rebuild.atmpl
cat: /usr/local/lib/argbash/argbash-lib.m4: Permission denied
cat: /usr/local/lib/argbash/output.m4: Permission denied
Error during autom4te run, aborting!
BASHdan@ShuPro /Users/dan/bin/bash >>sudo chmod -R 755 /usr/local/bin/argbash*
BASHdan@ShuPro /Users/dan/bin/bash >>argbash rebuild.atmpl
cat: /usr/local/lib/argbash/argbash-lib.m4: Permission denied
cat: /usr/local/lib/argbash/output.m4: Permission denied
Error during autom4te run, aborting!
BASHdan@ShuPro /Users/dan/bin/bash >>sudo chmod -R 755 /usr/local/lib/arg*
BASHdan@ShuPro /Users/dan/bin/bash >>argbash rebuild.atmpl
/
dan@ShuPro /Users/dan/bin/bash >>argbash rebuild.atmpl
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/m4:stdin:11: cannot open `collectors.m4': No such file or directory
autom4te: /usr/bin/m4 failed with exit status: 1
Error during autom4te run, aborting!
I wasnt' sure if autoconf was installed so checked that:
BASHdan@ShuPro /Users/dan/bin/bash >>brew install autoconf
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 3 taps (homebrew/core, homebrew/php, caskroom/cask).
==> New Formulae
gocryptfs
==> Updated Formulae
homebrew/php/composer โ app-engine-java docfx faas-cli git-imerge hubflow pandoc-citeproc snapcraft stockfish
abnfgen coffeescript emscripten fn grpc libmicrohttpd quantlib sourcekitten swiftformat
amber diamond etcd gammaray heroku mercurial snakemake sslyze
Warning: autoconf 2.69 is already installed
So I think all my permissions are straightened out but my system doesn't seem to have the "collectors.m4" file.. Whatever that is. Is it a missing library.
#blocked.
Using the "optional & pos." online example and pasting that into shellcheck shows many issues:
$ shellcheck myscript
Line 59:
printf "%s\n" "The general script's help msg"
^-- SC1117: Backslash is literal in "\n". Prefer explicit escaping: "\\n".
Line 61:
printf "\t%s\n" "<positional-arg>: positional argument help msg"
^-- SC1117: Backslash is literal in "\t". Prefer explicit escaping: "\\t".
^-- SC1117: Backslash is literal in "\n". Prefer explicit escaping: "\\n".
Line 62:
printf "\t%s\n" "-o,--option: optional argument help msg (no default)"
^-- SC1117: Backslash is literal in "\t". Prefer explicit escaping: "\\t".
^-- SC1117: Backslash is literal in "\n". Prefer explicit escaping: "\\n".
Line 63:
printf "\t%s\n" "--print,--no-print: boolean optional argument help msg (off by default)"
^-- SC1117: Backslash is literal in "\t". Prefer explicit escaping: "\\t".
^-- SC1117: Backslash is literal in "\n". Prefer explicit escaping: "\\n".
Line 64:
printf "\t%s\n" "-h,--help: Prints help"
^-- SC1117: Backslash is literal in "\t". Prefer explicit escaping: "\\t".
^-- SC1117: Backslash is literal in "\n". Prefer explicit escaping: "\\n".
Line 162:
echo "Value of positional-arg: $_arg_positional_arg"
^-- SC2154: _arg_positional_arg is referenced but not assigned.
$
Please let all shellcheck tests passโฆ
Hi,
# ARG_LEFTOVERS( .... )
produces
_our_args=$((${#_positionals[@]} - ${#_positional_names[@]}))
for (( ii = 0; ii < _our_args; ii++))
do
_positional_names+=("_arg_leftovers[(($ii + 0))]")
done
but has to be
for (( ii = 0; ii < $_our_args; ii++))
Tested in the online version as of today.
Best regards,
Christian
At the end of guide.rst, there is a bash array
text that links to nowhere.
Repeated arguments collect values to a bash array.
When a script has required positionals it should not throw an error if the user also passed --help
. The help is displayed but it prevents using a custom help function via ARG_OPTIONAL_ACTION([help]..)
, as die()
always calls the default print_help
. A user has to call ./foo.sh asd --help
to see the custom help function.
Also ./foo.sh --help
ending with FATAL ERROR: ....
is probably not the best user experience.
Docopt is a great tool to build command-line interfaces from help messages.
Argbash-generated scripts could construct help messages in such way that they could serve as docopt input. This would add these benefits:
Calling ARG_POSITIONAL_INF
using its minimal signature causes a cryptic error.
#!/bin/bash
# ARG_POSITIONAL_INF([something], [bla bla])
# ARGBASH_GO
You say in the doc here that with the long argument we can use \n to go to the next line.
However, when I did this the help print the "\n" rather than going to the next line.
After trying in my terminal I saw for printf "%s\n" "\nsalut"
that the \n in the first string is used as new line and the one in the second string is printed as "\n"
Hi,
I'm having some trouble updating argbash to v2.6.1 from v2.5.1 on Ubuntu 16.04. Running make develop
or make install
completes, and argbash appears to work perfectly aside from a weird issue when attempting to get the version number on the command line. However when I run make check
I get the following:
make unittests
make[1]: Entering directory '/home/chris_l/argbash/resources'
autom4te -l m4sugar -I ../src/ -I ../tests/unittests ../tests/unittests/check-utils.m4 && autom4te -l m4sugar -I ../src/ -I ../tests/unittests ../tests/unittests/check-indentation.m4 && autom4te -l m4sugar -I ../src/ -I ../tests/unittests ../tests/unittests/check-list.m4 && autom4te -l m4sugar -I ../src/ -I ../tests/unittests ../tests/unittests/check-types.m4 && autom4te -l m4sugar -I ../src/ -I ../tests/unittests ../tests/unittests/check-arguments.m4 && true
../src/utilities.m4:1: warning: file `list.m4' included several times
../src/utilities.m4:1: warning: file `list.m4' included several times
../src/utilities.m4:1: warning: file `list.m4' included several times
make[1]: Leaving directory '/home/chris_l/argbash/resources'
make regressiontests
make[1]: Entering directory '/home/chris_l/argbash/resources'
diff -q ../tests/regressiontests/basic.sh ../tests/regressiontests/basic2.sh
test -z "shellcheck -x -e 2015" || shellcheck -x -e 2015 "../tests/regressiontests/basic.sh"
unrecognized option `-x'
Usage: shellcheck [OPTIONS...] FILES...
-e CODE1,CODE2.. --exclude=CODE1,CODE2.. exclude types of warnings
-f FORMAT --format=FORMAT output format
-s SHELLNAME --shell=SHELLNAME Specify dialect (bash,sh,ksh)
-V --version Print version information
../tests/regressiontests/Makefile:186: recipe for target 'stability' failed
make[1]: *** [stability] Error 3
make[1]: Leaving directory '/home/chris_l/argbash/resources'
Makefile:115: recipe for target 'check' failed
make: *** [check] Error 2
It appears to be complaining about the version of shellcheck I have installed, v0.3.7-5, and I just wasn't sure if there was anything wrong with argbash or if a newer version of shellcheck was required.
I don't see in the API a way to define a required named argument. If that is indeed not the case, I would like to request such an option.
Thanks!
Hi
Issue
Argbash doesn't seem to support ZSH ?
Symptom
When running with ZSH I'm seeing the following error:
Error during argument parsing, possibly an Argbash bug
Which points to the eval
line below
assign_positional_args ()
{
# We have an array of variables to which we want to save positional args values.
# This array is able to hold array elements as targets.
_positional_names=('_arg_task' )
for (( ii = 0; ii < ${#_positionals[@]}; ii++))
do
eval "${_positional_names[ii]}=\${_positionals[ii]}" || die "Error during argument parsing, possibly an Argbash bug." 1
done
}
Workaround
Runs fine with #!/bin/bash
Many thanks
Currently argument variables are initialized like this:
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_print=off
_arg_foo_option="boo"
This is problematic when using sub-parsers, as optionals that were already parsed by the main script are reset to it's defaults and not parsed again. Could parameter expansion be used instead?
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_print=${_arg_print:-off}
_arg_foo_option="${_arg_foo_option:-boo}"
Perhaps I am just doing wrong, but it seems inconsistent to me. The default value for a boolean is yes
or no
:
_arg_verbose=yes
_arg_download_only=no
But when the user supplies this argument, it is set to on
or off
:
_arg_download_only="on"
test "${1:0:5}" = "--no-" && _arg_download_only="off"
This means that I have to check for both variants in order to get it right consistently. This can't be the intention, right?
The documentation for ARG_OPTIONAL_REPEATED reads:
The default default is an empty array. The argument can be repeated multiple times, but instead of the later specifications overriding earlier ones (s.a. ARG_OPTIONAL_SINGLE does), arguments are gradually appended to an array. The form of the default is what you normally put between the brackets when you create bash arrays, so put whitespace-separated values in there
The other options for argbash will supersede their defaults, but the effect of using the default option in ARG_OPTIONAL_REPEATED means that this set of values will always be present in the resulting list and that the arguments specified at the command-line merely supplement them.
Either the documentation should reflect this behavior or it should be changed to behave more similarly to the other options.
Currently, the ARG_OPTIONAL_BOOL
does not behave optimally (see #2 ).
It seems to be a good idea to have more macros for switch-on, switch-off and both (as the current ARG_OPTIONAL_BOOL
somehow attempts to).
Currently, ARG_OPTIONAL_BOOL
assumes that one wants to switch something on (using long and short option) and autogenerating long option to switch something off. This falls on its head when one wants to switch something off.
Proposed behavior:
ARG_OPTIONAL_BOOL
will remain, it will autodetect whether it is in a switch-on or switch-off mode by examining the default (or the option whether it begins withno-...
, I'm not yet decided). It will use the provided long and short options for the detected mode, but it will also generate a long option for the opposite mode.
ARG_OPTIONAL_BOOL(no-video, v)
would make the script accept --no-video
, -v
, that would set _arg_video
(which would be on
by default) to off
, and --video
, that would set _arg_video
to on
, overriding possible previous occurence of -v
or --no-video
.ARG_OPTIONAL_BOOL(video, v)
would make the script accept --video
, -v
, that would set _arg_video
(which would be off
by default) to on
, and --no-video
, that would set _arg_video
to off
, overriding possible previous occurence of -v
or --video
.New macros would be introduced:
ARG_OPTIONAL_SWITCH_ON
will be introduced. It will accept long and short option (and no default since off
will be assumed as default).
ARG_OPTIONAL_SWITCH_ON(video, v)
would make the script accept --video
, -v
, that would set _arg_video
(which would be off
by default) to on
.ARG_OPTIONAL_SWITCH_OFF
will be introduced. It will accept long and short option (and no default since on
will be assumed).
ARG_OPTIONAL_SWITCH_OFF(no-video, v)
would make the script accept --no-video
, -v
, that would set _arg_video
(which would be on
by default) to off
.Currently my main.sh
has something like:
# DEFINE_SCRIPT_DIR([])
# INCLUDE_PARSING_CODE([main.argbash])
# ARGBASH_GO()
And main.argbash
has:
# ARG_OPTIONAL_BOOLEAN([foo],[f],[Use foo])
# ARG_POSITIONAL_SINGLE([bar],[File for bars])
However, it means that anyone reading main.sh
has to reference main.argbash
to see what variables it provides, and I've found myself in the situation of referencing a variable that I'd deleted from the included file.
So, it would be nice if either or both of (a) allow the # ARG_...()
to be defined in the main file and/or (b) auto-add a reminder block to the main file like:
# $_arg_foo: "Use foo"
# $_arg_bar: "File for bars"
When using argbash's docker image to convert the file:
#!/bin/bash
#
# This is a rather minimal example Argbash potential
# Example taken from http://argbash.readthedocs.io/en/stable/example.html
#
# ARG_OPTIONAL_SINGLE([option], [o], [optional argument help msg])
# ARG_OPTIONAL_BOOLEAN([print], , [boolean optional argument help msg])
# ARG_POSITIONAL_SINGLE([positional-arg], [positional argument help msg], )
# ARG_HELP([The general script's help msg])
# ARGBASH_GO
# [ <-- needed because of Argbash
echo "Value of --option: $_arg_option"
echo "print is $_arg_print"
echo "Value of positional-arg:
using the script:
#!/bin/bash
docker run -it --rm -e PROGRAM=argbash \
-v "$(pwd):/work" \
matejak/argbash "$@"
to convert:
argbash test.sh > test_argbash.sh
chmod +x test_argbash.sh
one gets a file that fails to execute with bizarre errors:
Failed to execute process './test_argbash.sh'. Reason:
', which is not an executable command. the interpreter '/bin/bash
Looking into this a bit, and redirecting like so:
./test_argbash.sh 2>&1 | less
one gets something clearer:
Failed to execute process './test_argbash.sh'. Reason:
The file './test_argbash.sh' specified the interpreter '/bin/bash^M', which is not an executable command.
You might want to run shellcheck over al your .sh
files in your unit tests in order to assure they are good.
I do it like that.
Argbash 2.4.0 fails on the following input:
#!/bin/bash
#
# This is a rather minimal example Argbash potential
# Example taken from http://argbash.readthedocs.io/en/stable/example.html
#
# ARG_POSITIONAL_SINGLE([command], [c], [optional argument help msg])
# ARG_OPTIONAL_BOOLEAN([verbose], , [if set, output will be verbose])
# ARG_VERSION([echo $0 v$VERSION])
# ARG_HELP([The general script's help msg])
# ARG_LEFTOVERS([define 1 or more input file; if ommited scripts can still act on different values of SLRUM_PROCID])
# ARGBASH_GO
producing a false alarm about unknown number of positional args before defining leftover arguments.
Hi,
I'm working on a bash framework using argbash, so first I'd like to thank you for this generator.
That said, I have a question and/or a request.
I'm using a lot the wrapping functionality, so lately I tried to something fancy to see if it was working :
# ARGBASH_WRAP([directory/stem])
I was pleased to see that it doesn't make the generator fail, but sadly the output is not working.
I was wondering if wrapping with the relative path of the stem is something you have or would consider or is it really not a question (and so, shouldn't the generator failed) ?
I should precise that I know of the --search
option and I use it, but in this precise case it is more of an organisation convenience as I provide a framework.
Some interaction with the user could be improved and made customizable, for instance:
Hi,
This is great tool
I just want to know about the license of the files generated by argbash.
May I choose the license I want for the generated code (Eg Apache 2.0) or is the generated code
supposed to have the BSD-3-Clause license ?
It would be fantastic if argbash could generate a framework for a bash-completion script that matches the arguments it accepts.
Hello, I'm currently looking for a clean way to get contextual help in a bash project of mine and stumbled across argbash
. Except for the lack of short argument clustering, which I can probably live with, it looks very promising. However after reading the docs and playing around a bit I'm not sure argbash
is a good fit for contextual help. The pattern is fairly common now in modern cli applications like git or docker:
# print main help, global options like --verbose and main commands with short description
./mainscript
# print help text for command, global options and options specific to this command
./mainscript <command> --help
I pretty much have no idea what I'm doing yet, but it looks like I would need a conditional # INCLUDE_PARSING_CODE([cmd-foo-parsing.sh])
instruction to get the desired behaviour. Maybe I'm missing something obvious here. Could you provide a rough example if this is possible or what the best approach for this would be using argbash
?
Ideally I would like to separate the parsing code completely and just regenerate some parsing templates occasionally when new commands/options are added.
Thanks!
Currently ARG_OPTIONAL_BOOLEAN
is displayed like so:
$ ./foo.sh --help
foo!
Usage: ./foo.sh [--(no-)no-deps]
-n,--no-deps,--no-no-deps: some description
With many of those the negating (no-)
text adds a lot of visual noise and can be borderline silly as in the above case. I would imagine that most people have no use for an option flag that equals the application's default value.
Proposal:
Remove the (no-)
and ,--no-<some-option>
portions in the help output for ARG_OPTIONAL_BOOLEAN
, or at least make it's display configurable.
The ARG_OPTIONAL_REPEATED
and ARG_OPTIONAL_INCREMENTAL
currently extend their defaults. It may make sense to give a possibility to pick the way defaults are handled, because there are legitimate use cases when users want the defaults to be forgotten if they supply value(s) to these commands (see #12 for more in-depth insights).
The proposal is to introduce two alternatives for each macro that is in question:
ARG_OPTIONAL_REPEATED_ADD
ARG_OPTIONAL_REPEATED_REPLACE
ARG_OPTIONAL_INCREMENTAL_ADD
ARG_OPTIONAL_INCREMENTAL_REPLACE
Those macros would accept the same arguments, but they would treat the defaults differently (and also the help message would have to be different).
Any feedback is welcome, but most importantly:
I'd like to create repeated option where user can select from one of allowed values. I'm using following code:
$ cat empty_group_value.m4
#!/bin/bash
# m4_ignore(
echo "This is just a script template, not the script (yet) - pass it to 'argbash' to fix this." >&2
exit 11 #)Created by argbash-init v2.4.1a
# ARG_HELP([<The general help message of my script>])
# ARG_OPTIONAL_REPEATED([myopt], , [foo,bar,])
# ARG_TYPE_GROUP_SET([MYGROUP], , [myopt], [foo,bar,])
# ARGBASH_GO
# [ <-- needed because of Argbash
echo "Value of --myopt: ${_arg_myopt[@]}"
# ] <-- needed because of Argbash
After compilation:
$ argbash -o empty_group_value.sh empty_group_value.m4
Non-empty single and repeated options works as expected:
$ ./empty_group_value.sh --myopt foo
Value of --myopt: foo
$ ./empty_group_value.sh --myopt foo --myopt bar
Value of --myopt: foo bar
But when I try to skip this option or even set it to empty string:
$ bash ./empty_group_value.sh
Value '' (of argument 'myopt') doesn't match the list of allowed values: 'foo', 'bar' and ''
$ bash ./empty_group_value.sh --myopt ''
Value '' (of argument 'myopt') doesn't match the list of allowed values: 'foo', 'bar' and ''
script doesn't accept that and even print misleading error message.
I'm running the code with latest updates of Red Hat Enterprise Linux 7.4:
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ m4 --version
m4 (GNU M4) 1.4.16
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Rene' Seindal.
This is what I get when running argbash through a docker container:
$ argbash --version
argbash v
It seems that the version number is missing. I would suggest fixing this issue: it's a small one, but undermines the confidence in argbash
performance.
Hey all,, thanks so much for your work on Argbash Matejak, all out tooling is powered by argbash anhd we absolutely love it!
We wrote this small wrapper for our argbash scripts to enable devs to easily work on bash files without the manual compilation step between, hopefully it will be of use to others :)
https://gist.github.com/CodingNinja/c736e6cff18a4b37322558b6bb9dd93e
The instructions indicate that you should run
make install PREFIX=/usr/bin
to get argbash installed system wide. But that puts it in /usr/bin/bin/argbash.
to do it and get the expected behavior, it should either read make install PREFIX=/usr
or update the Makefile
When I use online generation with ARGBASH_SET_INDENT and select to generate explanatory comments, the comment block beginning # Function that evaluates whether a value passed to an argument
is not appropriately commented.
using test.m4
#!/bin/bash
# m4_ignore(
echo "This is just a script template, not the script (yet) - pass it to 'argbash' to fix this." >&2
exit 11 #)
# ARG_VERSION([echo "test/1.0.0"])
# ARG_OPTIONAL_SINGLE([option])
# ARG_OPTIONAL_BOOLEAN([print])
# ARG_HELP([<The general help message of my script>])
# DEFINE_SCRIPT_DIR([script_dir)])
# ARG_DEFAULTS_POS()
# ARG_RESTRICT_VALUES([no-local-options])
# ARGBASH_SET_INDENT([ ])
# ARGBASH_GO
# [ <-- needed because of Argbash
printf 'Value of --%s: %s\n' 'option' "$_arg_option"
printf "'%s' is %s\\n" 'print' "$_arg_print"
# ] <-- needed because of Argbash
generated test.sh
#!/bin/bash
#
# ARG_VERSION([echo "test/1.0.0"])
# ARG_OPTIONAL_SINGLE([option])
# ARG_OPTIONAL_BOOLEAN([print])
# ARG_HELP([<The general help message of my script>])
# DEFINE_SCRIPT_DIR([script_dir)]))
# ARG_DEFAULTS_POS([])
# ARG_RESTRICT_VALUES([no-local-options])
# ARGBASH_SET_INDENT([ ])
# ARGBASH_GO()
# needed because of Argbash --> m4_ignore([
### START OF CODE GENERATED BY Argbash v2.6.1 one line above ###
# Argbash is a bash code generator used to get arguments parsing right.
# Argbash is FREE SOFTWARE, see https://argbash.io for more info
# Generated online by https://argbash.io/generate
# When called, the process ends.
# Args:
# $1: The exit message (print to stderr)
# $2: The exit code (default is 1)
# if env var _PRINT_HELP is set to 'yes', the usage is print to stderr (prior to )
# Example:
# test -f "$_arg_infile" || _PRINT_HELP=yes die "Can't continue, have to supply file as an argument, got '$_arg_infile'" 4
die()
{
local _ret=$2
test -n "$_ret" || _ret=1
test "$_PRINT_HELP" = yes && print_help >&2
echo "$1" >&2
exit ${_ret}
}
# Function that evaluates whether a value passed to an argument
# does not violate the global rule imposed by the ARG_RESTRICT_VALUES macro:
# _CASE_RESTRICT_VALUES([],
[The value must not match any long or short option this script uses],
[The value must not match anything that looks like any long or short option.])
# _INDENT_()$1: The name of the option
# _INDENT_()$2: The passed value
evaluate_strictness()
{
[[ "$2" =~ ^-(-(version|option|print|help)$|[vh]) ]] && die "You have passed '$2' as a value of argument '$1', which makes it look like that you have omitted the actual value, since '$2' is an option accepted by this script. This is considered a fatal error."
}
# Function that evaluates whether a value passed to it begins by a character
# that is a short option of an argument the script knows about.
# This is required in order to support getopts-like short options grouping.
begins_with_short_option()
{
local first_option all_short_options
all_short_options='vh'
first_option="${1:0:1}"
test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_option=
_arg_print="off"
# Function that prints general usage of the script.
# This is useful if users asks for it, or if there is an argument parsing error (unexpected / spurious arguments)
# and it makes sense to remind the user how the script is supposed to be called.
print_help ()
{
printf '%s\n' "<The general help message of my script>"
printf 'Usage: %s [-v|--version] [--option <arg>] [--(no-)print] [-h|--help]\n' "$0"
printf '\t%s\n' "-v,--version: Prints version"
printf '\t%s\n' "-h,--help: Prints help"
}
# The parsing of the command-line
parse_commandline ()
{
while test $# -gt 0
do
_key="$1"
case "$_key" in
# The version argurment doesn't accept a value,
# we expect the --version or -v, so we watch for them.
-v|--version)
echo "test/1.0.0"
exit 0
;;
# We support getopts-style short arguments clustering,
# so as -v doesn't accept value, other short options may be appended to it, so we watch for -v*.
# After stripping the leading -v from the argument, we have to make sure
# that the first character that follows coresponds to a short option.
-v*)
echo "test/1.0.0"
exit 0
;;
# We support whitespace as a delimiter between option argument and its value.
# Therefore, we expect the --option value, so we watch for --option.
# Since we know that we got the long option,
# we just reach out for the next argument to get the value.
--option)
test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
_arg_option="$2"
shift
evaluate_strictness "$_key" "$_arg_option"
;;
# We support the = as a delimiter between option argument and its value.
# Therefore, we expect --option=value, so we watch for --option=*
# For whatever we get, we strip '--option=' using the ${var##--option=} notation
# to get the argument value
--option=*)
_arg_option="${_key##--option=}"
evaluate_strictness "$_key" "$_arg_option"
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
--no-print|--print)
_arg_print="on"
test "${1:0:5}" = "--no-" && _arg_print="off"
;;
# See the comment of option '--version' to see what's going on here - principle is the same.
-h|--help)
print_help
exit 0
;;
# See the comment of option '-v' to see what's going on here - principle is the same.
-h*)
print_help
exit 0
;;
*)
_PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1
;;
esac
shift
done
}
# Now call all the functions defined above that are needed to get the job done
parse_commandline "$@"
# OTHER STUFF GENERATED BY Argbash
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || die "Couldn't determine the script's running directory, which probably matters, bailing out" 2
### END OF CODE GENERATED BY Argbash (sortof) ### ])
# [ <-- needed because of Argbash
printf 'Value of --%s: %s\n' 'option' "$_arg_option"
printf "'%s' is %s\\n" 'print' "$_arg_print"
# ] <-- needed because of Argbash
weirdness in test.sh lines 39-45 (see 42,43 missing indent conversion and comment prefix)
# Function that evaluates whether a value passed to an argument
# does not violate the global rule imposed by the ARG_RESTRICT_VALUES macro:
# _CASE_RESTRICT_VALUES([],
[The value must not match any long or short option this script uses],
[The value must not match anything that looks like any long or short option.])
# _INDENT_()$1: The name of the option
# _INDENT_()$2: The passed value
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.