Structure
~~~~~~~~~

These are not “pure” shell scripts, but are preprocessed first by
ecFlow. In general, they should be simple shell wrappers (ideally
generated by pyFlow, but that is beyond the scope of this document)
around a standalone script (or a short sequence of such scripts with
minimal logic), passing through any ecFlow-variable-derived options via
command line arguments. Where there are a large number of such
variables, they may be placed in a configuration file in the task's
temporary working directory that is then passed as a single command-line
argument.

Options that come not from ecFlow variables but directly from a
suite-level (or sub-suite component-level) configuration file (e.g.
current ``config.*.h`` or their successor) should be passed by one of
the following, depending how many need to be supplied:

#. individually as command-line arguments, if only a few are required;
#. via a temporary configuration file as with ecFlow-derived variables,
   if there are too many to pass individually;
#. by directly passing the entire higher-level configuration file, if a
   large portion of its content is required;
#. by passing a coherent sub-portion of the higher-level configuration
   structure, if a hierarchical configuration system is introduced in
   future.

In very limited cases, but only where it corresponds to a
well-established interface (e.g. specifying paths to certain tools),
options may be used to set environment variables instead; however as
these are effectively a form of global variable this should not be the
norm, and should *never* be done for options that may vary between
components of a suite. Exporting the entire content of ``config.*.h`` to
the environment via ``set -a / -o allexport`` is strongly deprecated.

In all cases, the interface to the called script should be well
documented, so that the script which actually does the work can be
tested outside of ecFlow. This called script must correctly report any
failure via a non-zero return code to the task wrapper.

In light of the above, *only* the header and footer of the task
wrappers, or the boilerplate code directly ``%include``\ d in them,
should include ecFlow substitutions (``%VAR%``, further ``%include``\ s
etc.) Called / sourced scripts should not include such syntax, as this
makes them impossible to use or test outside of ecFlow. *If* they are
deployed via a construct like this in the task wrapper:

::

    cat >$TMPDIR/script <<\EOF
    %includenopp <script>
    EOF
    chmod +x $TMPDIR/script

then this should *always* be done using ``%includenopp`` rather than
``%include`` to prevent such substitutions and the need to "double-up"
real ``%`` characters in the script. Similarly, this should be done with
``<<\`` rather than ``<<`` to prevent shell substitutions during
deployment (which should only happen at runtime). *However, future
alternative mechanisms for script deployment are possible but outside
the scope of this document, to be considered alongside the wider
evolution of workflow code for suite generation and deployment.*