clishe

NAME

clishe - A CLI Shell Library

DESCRIPTION

Provides a set of function for creating command line interface scripts in Bourne Again Shell (bash) easily.

See samples directory or EXAMPLES section below for examples.

INSTALLATION

Before building and installing clishe, make sure you have installed pod2man, pod2html, podchecker and shellcheck on your system.

Next, get the tarball and unpack it or, if you want the most recent snapshot, clone the clishe repository:

  $ git clone --recurse-submodules https://github.com/i386x/clishe.git

Inside the clishe top directory, type:

  $ make && make install

This will install clishe and all its documentation under the /usr/local location. To change the install destination, use PREFIX:

  $ PREFIX=/usr make install

This will install clishe under the /usr location.

USAGE

To use clishe, simply insert the following line to your script:

  . /usr/local/share/clishe/clishe.sh

You can also use a more robust way:

  SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
  CLISHEPATH="${SCRIPTDIR}:/usr/local/share/clishe:/usr/share/clishe"

  PATH="${CLISHEPATH}${PATH:+:}${PATH}" \
  . clishe.sh >/dev/null 2>&1 || {
    echo "clishe library is not installed"
    exit 1
  }

This will prefer bundled clishe.sh with your script over clishe.sh from /usr/local/share/clishe and clishe.sh from /usr/local/share/clishe over clishe.sh from /usr/share/clishe.

Do not forget also to initialize clishe before using anything from it:

  clishe_init

ENVIRONMENT VARIABLES

CLISHE_COLOR - set a color of text printed by clishe_echo. See clishe_echo for more details.

CLISHE_NOCOLOR - if non-empty, suppress colored output of clishe_echo. See clishe_echo for more details.

CLISHE_QUITE - if non-empty, suppress clishe_echo's output. See clishe_echo for more details.

CLISHE_HELP_INDENT1 - spaces before option name in help screen. See clishe_defopt.

CLISHE_HELP_INDENT2 - spaces before paragraph with option description. See clishe_defopt.

VARIABLES

clishe_scriptname - a base name of the script. See clishe_defopt for example of use.

clishe_helplines - holds the description of defined script options. See clishe_defopt.

clishe_nopts - a number of options processed by clishe_process_options. See clishe_process_options.

clishe_tailopts - a list of options that was on a tail of command line. See clishe_defopt and clishe_process_options for better explanation.

FUNCTIONS

Initialization

clishe_init

Initialize clishe shell library. This function should be invoked before any other function from clishe library is invoked.

Auxiliary functions

clishe_setvar

Globally set the value of a variable.

Usage:

  clishe_setvar VARIABLE VALUE
VARIABLE

A variable name.

VALUE

A value to be assigned to VARIABLE.

Assign VALUE to VARIABLE.

Reporting

clishe_echo

Print a text given in parameters to the standard output.

Usage:

  clishe_echo [-X|--red|--green|--blue|--yellow|--color COLOR_CODE] \
              [MSG1 [MSG2 [...]]]
-X

Option of the form -X is passed directly to echo, i.e.

  clishe_echo -n "foo"

is the same as

  echo -n "foo"
--red

Print text in red color.

--green

Print text in green color.

--blue

Print text in blue color.

--yellow

Print text in yellow color.

--color COLOR_CODE

Print text in COLOR_CODE color. The COLOR_CODE must be written in a way so

  \e[${COLOR_CODE}m

is a valid ANSI escape color code. For example

  clishe_echo --color '33;1' "foo"

prints foo in yellow to the terminal window.

MSG1 MSG2 ...

Messages to be printed. When printed, a space character is put between two messages.

To set a color, environment variable CLISHE_COLOR can be set to the value of the same format as in the case of COLOR_CODE. Therefore,

  CLISHE_COLOR='33;1' clishe_echo "foo"

prints foo in yellow. The value of CLISHE_COLOR can be overriden by command line arguments, so

  CLISHE_COLOR='33;1' clishe_echo --red "foo"

prints foo in red instead of yellow. If CLISHE_NOCOLOR has non-empty value, it suppresses color output entirely, no matter whether the color is set via CLISHE_COLOR or via command line. Thus,

  CLISHE_NOCOLOR=1 CLISHE_COLOR='33;1' clishe_echo --red "foo"

prints foo in default terminal colors. If CLISHE_QUITE is set, no output is printed. For example

  CLISHE_QUITE=1 CLISHE_COLOR='33;1' clishe_echo --red "foo"

prints nothing to standard output.

clishe_error

Print EMSG1 EMSG2 ... to the standard error output in red and exit with exit code N (if N is not specified, exit with 1).

Usage:

  clishe_error [N] [EMSG1 [EMSG2 [...]]]
N

Exit code. Must be a positive integer. Default exit code is 1.

EMSG1 EMSG2 ...

Error messages to be printed to the standard error output.

If the first argument matches ^[1-9][0-9]*$ (that is, if the first argument is a positive integer), it is treated as exit code instead of message text. Therefore

  clishe_error "Foo:" "error"

prints Foo: error to the standard error output and exit with 1 whereas

  clishe_error 2 "Foo:" "error"

prints the same but exit with 2.

As clishe_error uses clishe_echo, its output can be influenced by CLISHE_NOCOLOR and CLISHE_QUITE environment variables.

Options

clishe_defopt

Define a command line option.

Usage:

  clishe_defopt --key=STORAGE [-a [-b [...]]] -- HELP \
                ( required | optional [DEFAULT] )
  clishe_defopt --flag [-a [-b [...]]] -- HELP ( STORAGE | help ACTION )
  clishe_defopt STORAGE HELP
  clishe_defopt @NAME HELP

Above, there are four forms of how to use clishe_defopt. The first form is a way of how to define key-value option. The second form is a way of how to define flag option.

The third form provide a way of how to tell clishe that there are positional options to be processed before key-value and flag options arrive. Thus

  clishe_defopt USER "user name"
  clishe_defopt EMAIL "user email"
  clishe_defopt --help -h -- "print this screen and exit" help usage
  ...

tells to clishe that the first command line option is should be stored to USER, the second one to EMAIL, and the following are processed as key-value options and flags (or as tail options, see the next paragraph). Note that the order of definitions is important. If we alter first and second definition, we must also alter first and second option on command line. Also note that positional options are mandatory, so if one of them is missing it is treated as error (this does not hold for help options; in case that the help option is encountered, help action is performed even if command line options do not met the specification, except the situation when help option comes as a value of key-value option that consumes it).

The last, fourth, form tells to clishe that after the last key-value or flag option arrive zero to n positional options, called tail options. The sequence of tail options ends if command line ends or if -- was encountered. Tail options are optional, the start of tail options sequence is determined by the first option on command line that not start with dash (-). Anything between the first tail option and -- or end of command line is treated as a tail option. The processed tail options are stored to clishe_tailopts array.

--key=STORAGE

This form of the first argument specify that the defined option is key-value option. key is the name of the option, STORAGE is the name of the variable to which a value of --key given on command line should be stored.

--flag

This form of the first argument specify that the defined option is flag option named flag.

-a -b ...

A list of short options which works as an aliases/shortcuts for the long one. The list is terminated with --.

HELP

A help text to be displayed as the description of the defined option. If this option is empty (""), the help text is read from the standard input. If the option is optional key-value option, the information about its default value is appended to the help text.

The help text is accumulated in clishe_helplines variable that can be used in user defined help printing routines. Environment variables CLISHE_HELP_INDENT1 and CLISHE_HELP_INDENT2 influence the indentation of help text. Given an excerpt of help screen

  Usage: script.sh [OPTIONS]
  where OPTIONS are

    --help, -h, -?
        print this screen and exit

the spaces that are before --help, -h, -? are taken from CLISHE_HELP_INDENT1 whereas the spaces before print this screen and exit comes from CLISHE_HELP_INDENT2. If no CLISHE_HELP_INDENT1 or CLISHE_HELP_INDENT2 are provided, the default amount of spaces is 2 and 6, respectively. Because the help text is assembled dynamically during clishe_defopt invokation, it is recommended to set them before a first use clishe_defopt.

required

The keyword required is applicable to key-value options only. It says that the key-value option must be present on the command line and its value must be non-empty.

optional

The keyword optional is applicable to key-value options only and it says that the key-value option is optional.

DEFAULT

A default value of the key-value option if it was declared as optional. The default value should be specified only in connection with optional keyword. If no default value is specified, the default value of key-value option is the empty string.

STORAGE

A name of a variable to which the presence of flag option should be recorded. The storage variable holds the number of occurences of flag option on command line. If the corresponding flag option was not encountered during the command line processing, the storage variable remains unset. Thus, to test whether the flag option has been set, use

  [[ ${STORAGE_VARIABLE:-0} -gt 0 ]]

In case of

  clishe_defopt STORAGE HELP

form, STORAGE is a name of a variable to which a positional argument will be stored.

help

The keyword help indicates that the flag option fires a function that print a help screen.

ACTION

Applicable only with help, the ACTION is the name of function that is responsible for printing of help screen.

@NAME

@ serves for distinguishing between third form and fourth form of clishe_defopt. NAME is a string that is displayed on help screen, thus

  clishe_defopt "@FILE1 FILE2 ..." "input files"

will result in

  FILE1 FILE2 ...
      input files

Following examples demonstrate how to define command line options. Consider an excerpt from a script script.sh:

  clishe_defopt VMNAME "virtual machine name"
  clishe_defopt --token=TOKEN -t -- "a security token" required
  clishe_defopt --port=PORT -p -- "port number" optional 8888
  clishe_defopt --email=EMAIL -- "email address" optional
  clishe_defopt --verbose -v -- "verbosity level" V
  clishe_defopt --help -h -? -- "" help usage <<__HELP__
  print this screen and exit
  __HELP__
  clishe_defopt @FILES "input files"

  function usage() {
    cat <<EOF
  Usage: ${clishe_scriptname} VMNAME [OPTIONS] [FILES...]
  where options are

  ${clishe_helplines}

  EOF
    exit 0
  }

If we run

  $ ./script.sh myvm -tfa1afe1 -port=7777 -vvv

then the value of VMNAME will be myvm, the value of TOKEN will be fa1afe1, the value of PORT will be 7777, the value of EMAIL will be its default value which is the empty string, and the value of V will be 3 because there are 3 occurences of v option on command line.

If we run

  $ ./script.sh myvm --token=fadeb1ade x.o y.o --help z.o

then the value of VMNAME will be myvm, the value of TOKEN will be fadeb1ade, PORT and EMAIL will keep their default values, and clishe_tailopts will contain x.o, y.o, --help and z.o. Observe that --help in this case will not print help screen.

If we run

  $ ./script.sh vm1 vm2 --token=fadeb1ade --help x.o

then we get an error about missing --token option, because the vm1 is passed to VMNAME and, since vm1 not starts with dash, the rest of options are treated as tail options.

If we just run

  $ ./script.sh myvm -v

we get an error about missing --token option, because this option is marked as required. If we omit myvm, we get an error about missing positional option VMNAME.

Printing the help screen is done via usage function. Notice that instead of --help, options -h and -? can be also used to show the help:

  $ ./script.sh -?
  Usage: script.sh VMNAME [OPTIONS] [FILES...]
  where options are

    VMNAME
        virtual machine name

    --token=TOKEN, -t
        a security token

    --port=PORT, -p
        port number
        (default: "8888")

    --email=EMAIL
        email address
        (default: "")

    --verbose, -v
        verbosity level

    --help, -h, -?
        print this screen and exit

    FILES
        input files

clishe_process_options

Process command line options and store the number of processed options to clishe_nopts.

Usage:

  clishe_process_options [OPT1 [OPT2 [...]]]

The general format of command line is

  <positional opts> <key-value and flag opts> <tail opts> -- <the rest>

positional opts are specified with the third form of clishe_defopt, key-value and flag opts are specified with the first and second form of clishe_defopt and tail opts are specified with the fourth form of clishe_defopt and they are stored into clishe_tailopts array. -- works as the options end marker, the rest remains unprocessed.

OPT1 OPT2 ...

Options to be processed. If one of the options is --, the processing is terminated.

Given an excerpt from script.sh

  clishe_process_options "$@"

after running script.sh as

  $ ./script.sh --foo=bar -x -- a b c

options --foo=bar and -x will be processed. When -- will be reached, it will be consumed and the processing of options will be terminated. The value of clishe_nopts variable becomes 3. The value of clishe_nopts can be used for shifting command line options to get the access to the yet unprocessed part of command line.

EXAMPLES

The following Bash script prints information about its argumetns:

  #!/bin/bash

  set -euo pipefail

  SCRIPTDIR="$(readlink -f "$(dirname "$0")")"
  CLISHEPATH="${SCRIPTDIR}:/usr/local/share/clishe:/usr/share/clishe"

  PATH="${CLISHEPATH}${PATH:+:}${PATH}" \
  . clishe.sh >/dev/null 2>&1 || {
    echo "clishe library is not installed"
    exit 1
  }

  clishe_init

  clishe_defopt ARG1 "positional argument #1"
  clishe_defopt ARG2 "positional argument #2"
  clishe_defopt --token=TOKEN -t -- "security token" required
  clishe_defopt --user=USER -u -- "" optional "Jane Doe <jd@compant.com>" <<EOF
  a user name and email; please, keep the following format

    Name Surname <your@email.address>

  the email part is optional
  EOF
  clishe_defopt --prefix=PREFIX -- "prefix" optional
  clishe_defopt --verbose -v -- "verbocity level" V
  clishe_defopt --help -h -? -- "print this screen and exit" help usage
  clishe_defopt "@FILE1 FILE2 ..." "input files"

  function usage() {
    cat <<-EOF
        Show options (a clishe demo).

        Usage: ${clishe_scriptname} ARG1 ARG2 [OPTIONS] [FILE1 [FILE2 [...]]]
        where options are

        ${clishe_helplines}

        The key-value options with no default value are required.

        EOF
    exit 0
  }

  clishe_process_options "$@"
  shift ${clishe_nopts}

  clishe_echo --blue "ARG1: '${ARG1:-}'"
  clishe_echo --blue "ARG2: '${ARG2:-}'"
  clishe_echo --blue "TOKEN: '${TOKEN:-}'"
  clishe_echo --blue "USER: '${USER:-}'"
  clishe_echo --blue "PREFIX: '${PREFIX:-}'"
  clishe_echo --blue "V: ${V:-0}"
  clishe_echo --blue "Files: ${clishe_tailopts[@]}"
  clishe_echo --blue "Processed options: ${clishe_nopts}"
  clishe_echo --blue "Rest of options: $*"

AUTHORS

VERSION

LICENSE

BUG REPORTS

If you found a bug, please open an issue.