.. _invocation: Argbash tools ============= .. _file_layout: ``Argbash`` is a code generator, so what it does, it gives you code that has the ability to parse command-line arguments. The question is --- what to do with the generated code? You have three options here, they are sorted by the estimated preference: #. One file with both parsing code and script body --- batteries are included! This is a both simple and functional approach, but the argument parsing code will pollute your script. #. Two files --- one for the parsing code and one for the script body, both taken care of by ``Argbash`` --- separation of code, but you get things managed by ``Argbash``.. This is more suitable for people that prefer to keep things tidy, you can have the parsing code separate and included in the script at run-time. However, ``Argbash`` can assist you with that. #. Same as the above, just without ``Argbash`` assistance --- the parsing code is decoupled from the script. You have to take this path if your script has a non-matching square brackets problem (see :ref:`limitations`). This approach is similar to the approach of ``bash`` argument parsing libraries with one difference --- here, the library is generated by ``Argbash``, so it may be significantly less complex than those generic libraries such as :ref:`EasyOptions `. This is very unlikely. .. note:: We assume that you have installed (see :ref:`install`) the ``argbash`` script, so it is available in your terminal as a command ``argbash``. If it is not the case, you just have to substitute ``argbash`` by direct invocation of ``bin/argbash``. .. _argbash_init: Template generator ------------------ It is not advisable to write a template from scratch, since ``Argbash`` contains a tool for that. The ``argbash-init`` :ref:`can generate ` a good starting template for you, so you can get started within minutes. .. _argbash_init_general: General usage +++++++++++++ The most efficient way of using ``Argbash`` is probably this one (also covered in an :ref:`example `): #. Get an idea of what arguments your script should accept. #. Execute ``argbash-init`` with the right arguments to get a basic template. #. Replace placeholders in the template with meaningful values. #. Expand the template with another directives (if necessary) based on :ref:`argbash API `. #. Run ``argbash`` over the template. ``argbash-init`` supports generating templates with these types of arguments: * Single-valued positional arguments (``--pos`` argument). * Single-valued optional arguments (``--opt`` argument). * Boolean optional arguments (``--opt-bool`` argument). Generally, you specify argument name and you add help etc. by editing the template file. Next, ``argbash-init`` supports :ref:`wrapping ` of another argbash-aware scripts. The help macro is always included. .. _argbash_init_modes: Modes of operation ++++++++++++++++++ ``argbash-init`` allows you to select the way how the parsing code is handled (via the ``-s``, ``--standalone`` option): * Batteries-included mode: If you don't specify it, you get the case 1 from above --- the parsing code is embedded in the script. * Managed mode: If you specify it exactly once, you get the case 2 from above --- parsing code is in a separate file, but both files contain ``Argbash`` directives. * Decoupled mode: If you specify twice, you get the case 3 from above --- parsing code is in a separate file, the script includes it without any magic involved. This also means that the :ref:`brackets matching limitation ` doesn't apply to you. There is also a ``--mode`` option you can use to tune the balance between parsing features and complexity of the generated code. * ``default``: Assume the standard ``Argbash`` behavior. Check the documentation out to find out what that means. * ``full``: Maximize script features. * The long option and the corresponding value may be separated by whitespace or by the equal sign. * Variables corresponding to every positional argument is declared (.. seealso::`_declare_pos`). * ``minimal``: Make the code as simple as possible, which means: * The long option and the corresponding value may be separated only by whitespace. Argbash ------- So, you have a template and now it is time to (re)generate a shell script from it! Template layout +++++++++++++++ A template consists of multiple parts that are treated differently during the ``argbash`` operation. Depending on the value of the ``--strip`` argument, the third and/or the first parts can be dropped. Here are those parts of the template: #. Beginning of the script up to the ``ARGBASH_GO`` or ``ARGBASH_PREPARE`` line: If ``--strip all`` is passed as argument to ``argbash``, this section of the file will be discarded. Otherwise, it is left intact, except: - All ``m4sugar`` macros are expanded. Typically, the only macros in this section are Argbash public API macros. They expand to their definitions as part of their expansion, so it looks like that nothing happened. - One level of square brackets is removed. This is the consequence of the previous point --- if you e.g. use a regular expression with square brackets, they may either disappear or cause an error. Square brackets that are arguments to the Argbash macros calls are preserved. #. Script body past ``ARGBASH_GO``: This is the generated content. Shortly after the ``ARGBASH_GO`` line, you encounter an invocation of ``m4_ignore([...])``. Everything contained within the first level of the square brackets is discarded by a consecutive run of ``argbash``. #. The rest of the file. If you run ``argbash`` with ``--strip user-content`` or ``--strip all`` argument, this section will be missing from the output altogether. Otherwise, the preexisting content is preserved with some noteworthy points: - You may notice the ``# [ <-- needed because of Argbash`` and ``# ] <-- needed because of Argbash`` guards. The first guard has an opening square bracket, the second guard at the bottom of the file has a closing square bracket. Don't remove them, they are necessary for ``argbash`` to be idempotent. - This part of the file (typically the hand-written content supplied by the user) is treated in the same way as the beginning of the file that is described in point 1. However, thanks to the opened and closed square brackets, no changes to it will be made. Parsing code and script body together +++++++++++++++++++++++++++++++++++++ Assuming that you have created a template file ``my-template.m4``, you simply run ``argbash`` over the script [*]_: :: argbash my-template.m4 -o my-script.sh If you want to regenerate a new version of ``my-script.sh`` after you have modified its template section, you can run :: argbash my-script.sh -o my-script.sh as the script can deal with input and output being the same file. .. [*] ``m4`` is the file extension used for the ``M4`` language, but we use the ``m4sugar`` language extension built on top of it. Separate file for parsing with assistance +++++++++++++++++++++++++++++++++++++++++ You have two files, let's say it is a ``my-parsing.m4`` and ``my-script.sh``. The ``my-parsing.m4`` file contains just the template section of ``my-script.sh``. Then, you add a very small template code to ``my-script.sh`` at the beginning: .. code-block:: bash # DEFINE_SCRIPT_DIR # INCLUDE_PARSING_CODE([my-parsing.sh]) # ARGBASH_GO # [ <-- needed because of Argbash # HERE GOES THE SCRIPT BODY # ] <-- needed because of Argbash i.e. you add those three lines with definitions and you enclose the script in square brackets. Finally, you just make sure that ``my-script.sh`` and ``my-parsing.m4`` are next to each other and run :: argbash my-script.sh -o my-script.sh which finds ``my-parsing.m4`` (it would find ``my-parsing.sh`` too) and generates new ``my-parsing.sh`` and ``my-script.sh`` that you can use right away. If both ``my-parsing.m4`` and ``my-parsing.sh`` are found, the more recent one is used to generate the ``my-parsing.sh``. .. _usage_manual: Separate file for parsing +++++++++++++++++++++++++ If you want/have to take care of including the parsing code yourself, just make sure you do it in the script --- for example: .. code-block:: bash source $(dirname $0)/my-parsing.sh # HERE GOES THE SCRIPT BODY Then, you just generate ``my-parsing.sh`` using ``--strip user-content`` option: .. code-block:: bash argbash my-parsing.m4 -o my-parsing.sh --strip user-content The ``--strip user-content`` argument takes care that the output will contain the Argbash definitions lines and the generated parsing code, but the body of the script will not be included. .. _commented: Commented output ++++++++++++++++ You can call ``argbash`` in commented mode, when the generated code is commented, so you can run through the generated code and understand the big picture fast. To generate code with those comments, just call ``argbash`` with the according switch: .. code-block:: bash argbash my-parsing.m4 -c -o my-parsing.sh Argbash outputs --------------- Argbash is able to generate more than just scripts. You can change the output type by supplying another value to he ``--type`` optional argument. Next, it doesn't make sense to keep all of the template content in the output, so you may typically want to strip all but the generated content from alternative outputs: ============================ ======================= ========================== Description ``--type`` value ``--strip`` value ============================ ======================= ========================== Bash script bash-script none Bash script parsing section bash-script user-content POSIX script posix-script none POSIX script parsing section posix-script user-content Bash completion completion all docopt help message docopt all manpage template manpage all manpage template definitions manpage-defs all No generated code excised all ============================ ======================= ========================== .. _posix: POSIX script ++++++++++++ Argbash is able to generate code that will work with POSIX shells. Due to limitations of those shells (mainly absence of arrays), the generated interface features are limited: * All options have to have short option. Those short options are the only user-visible element of the interface. * Mixing optional and positional arguments is not supported, all arguments that follow the first positional argument are considered positional. * Certain arguments are not supported: * Repeated arguments. * Multi-valued arguments. Internally, Argbash uses the ``getopts`` shell builtin to handle optional arguments parsing. Then, checks for positional arguments are generated and applied, ditto for positional arguments processing, and the help message is generated. As a result, the parsing section of a POSIX script is shorter. Bash completion +++++++++++++++ The output will be a Bash completion script. Notice that in this case, the completion file has to "know" the basename of the script the completion is meant for. The basename is inferred either from the source filename, or from the destination by stripping the ``.m4`` suffix if applicable .. note:: The general recommendation is not to save your scripts to files without suffixes. Keep the ``.sh`` suffix only for files that are Bash modules. After you generate the completion file, put it in the appropriate place (which may vary depending on your environment). In order to use it right away, simply source it. Typically, you generate bash completion ``my-script.sh`` from the generated script ``my-script`` by executing .. code-block:: shell-session $ argbash my-script --type completion --strip all -o my-script.sh and you move the created completion file ``my-script.sh`` to ``/etc/bash_completion.d/`` directory. .. note:: Completion is not implemented for positional arguments. The corresponding Bash completion algorithm has to be much more complex in order to distinguish between 1st, 2nd etc. positional arguments. .. _docopt_output: Docopt help message +++++++++++++++++++ `Docopt `_ is a project that provides argument-parsing libraries for various languages. Those libraries accept a help message as an input, and that's all they want to construct a parser. Argbash scripts don't come with help that conforms to the ``docopt`` format due to its constraints, but you can still generate ``docopt``-compliant help for your script. This allows you to use Argbash for projects in other languages --- you can leave the parser technicalities to docopt library, which you supply with the Argbash docopt output. Then, you may use Argbash for Bash completion and other possible goodies. Typically, you generate docopt output to the standard output from the generated script ``my-script`` by executing .. code-block:: shell-session $ argbash my-script --type docopt --strip all .. note:: Docopt output doesn't work with likes of the :ref:`decoupled mode `. You can't pass the script which sources the parsing code as Argbash input, as it doesn't contain any Argbash macros. If you pass the parsing code script/template as Argbash input, the output will have wrong basename, as Argbash will use the basename of the parsing code file, not of the real script. .. _manpage_output: Manpage output ++++++++++++++ Argbash can generate source for the manual page for your script. There are two files in the process --- the template, and definitions. Those two files are in the `reStructuredText `_ format, and the template is supposed to be processed by the `rst2man `_ utility. The manpage template is supposed to be generated as script's metadata change, definitions are required to be maintained manually, as they are supposed to contain content that is not present in the script. You can regenerate the template using the ``manpage`` output, while you are probably going to use the ``manpage-defs`` once to get you kickstarted and then continue to maintain it manually. So given a argbash-powered script or m4 file, your manpage workflow will typically look like this: .. code-block:: shell-session $ argbash my-script --type manpage-defs --strip all -o my-script-defs.rst $ argbash my-script --type manpage --strip all -o my-script.rst $ vim my-script-defs.rst # Edit the definitions file $ rst2man my-script.rst > my-script.1 $ man ./my-script.1 .. _excise_output: Output without generated code +++++++++++++++++++++++++++++ Argbash can also generte output that doesn't contain parsing code --- only user code and the Argbash template. If the input contained parsing code, that one gets *excised*. There are following examples when the excised output makes sense when dealing with Argbash-powered scripts: - Space saving for e.g. copy-pasting: Don't involve generated code earlier than you need to, as it does make the script larger, and that can be an annoyance. - Normalization of scripts for storage: Store only definitions that are less likely to change, and generate implementation of parsing using the latest greatest version of Argbash just in time. .. _api_change: API changes support ------------------- The API of the ``Argbash`` project may change. This typically means that * names, parameters or effect of macros change, or * parsed arguments are exposed differently in a way that is not compatible with the previous API. In case that you regenerate a script, ``argbash`` is able to deduce that it has been created with another version of ``Argbash`` and warns you. In that case, you can use a ``argbash-xtoy`` script, where ``x`` is the version of ``Argbash`` your script is written for and ``y`` is version of ``Argbash`` you use now. To upgrade your script from ``Argbash`` version 1 to 2, you simply invoke: .. code-block:: bash argbash-1to2 my-script.sh -o my-script.sh You can use the utility to convert scripts as well as ``.m4`` templates. .. warning:: Always back your scripts up and perform diff between the output and the original after using ``argbash-xtoy``. API 2 +++++ Parsed arguments were exposed as lowercase (``_ARG_LONG_OPTION`` became ``_arg_long_option``). The change was motivated by effort to comply to bash standard variable naming convention [#]_, [#]_. .. [#] `Unix StackExchange `_ .. [#] `Google bash styleguide `_