UNIX shell command line parser API

This document describes the functions and variables generated by build-shellscript

API

Any undocumented function you may find in a generated script should have to be considered as a private function.

Functions

Name Parameters Return value Description
parse() argv The number of error encountered Parse the command line arguments and fill the options bound variable and the $parser_values array
parse_displayerrors() None 0 Output all errors generated while parsing the command line
usage() [topic] 0 Print the program help string, generated from the information gathered in the XML program description file.
if topic is the name of a subcommand, usage will display the program's subcommand help string.

Variables

Name Type Description
$parser_shell string The name of the shell interpreter (example: bash)
$parser_startindex int Indicates what is the first valid index in a array variable (0 in bash, 1 in zsh)
$parser_subcommand string Name of the selected program subcommand. The name is always the one described by the <name /> element even if one of it aliases was used on the command line
$parser_values array Array of positional arguments which are not subcommand names, option names, option arguments nor special markers

Options bound variables

For each program option defined in the program interface XML definition file where a variable name is defined,

  <!-- (...) -->
  <databinding>
    <variable>displayHelp</variable>
  </databinding>
  <!-- (...) -->

a shell variable of the same name is created with the following rules

Option type Variable type Default value
Switch Boolean false
Single argument String Value of <default/> if any,
Empty string otherwise
Multi argument Array Empty
Group String Empty string

After parsing, variables are modified as is

Option type Value
Switch true if the option is present on the command line
Single argument Value of the option argument if the option is present on the command line.
Multi argument Values of the option arguments if the option is present on the command line.
Group If the group is exclusive: Name of the first sub option bound variable name found on the command line;
Otherwise, an empty string

Tweaking

Subcommand option variable names

The program interface definition schema allows options of two subcommands to share the same bound variable name. To avoid name aliasing while generating the bash code, the subcommand option variable names can be prefixed with the name of the subcommand using the --prefix-sc-variables option of build-shellscript

If the subcommand sub has an option with a bound variable name myVar, the variable name will become sub_myVar.

Preprocessing

Any option's bound variable can be modified prior to calling the parse function. This can be useful to set a default value which depends on dynamic data

# ... auto generated function and variables are above

# Set a default value for ${outputFile} using the current date
outputFile="/tmp/filename-$(date +%F).tmp"

# Call parser
if ! parse "${@}"
then
  exit 1
fi

echo "outputFile = ${outputFile}"
exit 0

Code snippets

Calling the parser

We assume the program has a --help switch option with a bound variable name displayHelp

  <!-- (...) -->
  <switch id="prg.option.displayHelp">
    <databinding>
      <variable>displayHelp</variable>
    </databinding>
    <documentation>
      <abstract>Display program usage</abstract>
    </documentation>
    <names>
      <long>help</long>
    </names>
    <ui mode="disabled" />
  </switch>
  <!-- (...) -->

The first lines of your program should looks like

# Call the parser
if ! parse "${@}"
then
  # If an error occurs but the --help switch is present, just print help
  if ${displayHelp}
  then
    usage ${parser_subcommand}
    exit 0
  fi
 
  # else, display errors and exit
  parse_displayerrors
  exit 1
fi

# Handle --help option
if ${displayHelp}
then
  usage ${parser_subcommand}
  exit 0
fi

# The real work begins...

Accessing positional arguments

Let's say we are re-coding the mv utility. The n-1 positional arguments are the input files, the last positional argument is the output file or folder

  <!-- (...) -->
  <!-- some options -->
  <!-- (...) -->
  <values>
    <other>
      <type>
        <path access="r" />
      </type>
    </other>
  </values>
  <!-- (...) -->

To process positional arguments, use the ${parser_values} array

total_values=${#parser_values[*]}
if [ ${total_values} -lt 2 ]
then
  echo "Missing arguments"
  exit 2
fi

is_multi_copy=false
if [ ${total_values} -gt 2 ]
then
  is_multi_copy=true
fi

# This is for Bash
output_index=$(expr ${total_values} - 1)
# And this is for Zsh
# output_index=${total_values}

output=${parser_values[${output_index}]}
if ${is_multi_copy} && [ ! -d "${output}" ]
then
  echo "${output} have to be a folder"
  exit 1
fi

for ((i=0;${i}<${output_index};i++))
do
  echo "Moving ${parser_values[${i}]} to ${output}"
done

Dealing with exclusive groups

Three single-argument options in an exclusive group.

  <group type="exclusive">
    <databinding>
      <variable>groupVariable</variable>
    </databinding>
    <options>
      <argument>
        <databinding>
          <variable>firstArg</variable>
        </databinding>
        <names>
          <long>basic-argument</long>
        </names>
      </argument>
      <argument>
        <databinding>
          <variable>secondArg</variable>
        </databinding>
        <names>
          <long>string-argument</long>
        </names>
        <type>
          <string/>
        </type>
      </argument>
      <argument>
        <databinding>
          <variable>thirdArg</variable>
        </databinding>
        <names>
          <long>argument-with-default</long>
        </names>
        <default>Default value</default>
      </argument>
    </options>
  <group>

Since ${thirdArg} will always have a non-null value (due to the <default/> clause), we can't rely on variable emptyness to know which option the user selects. We have to use the group bound variable ${groupVariable}

case "${groupVariable}" in
  "firstArg")
    echo "You select the first option: ${firstArg}"
    ;;
  "secondArg")
    echo "You select the second option: ${secondArg}"
    ;;
  "thirdArg")
    echo "You select the third option: ${thirdArg}"
    ;;
  *)
    echo "Well, since the group is not required, it's ok to select none"
    ;;
esac

The program interface definition framework