Bash Processing of Command Line Parameters that Include Spaces

From NovaOrdis Knowledge Base
Jump to: navigation, search

Internal

Overview

This page documents coding patterns to be used when some of the command line parameters need to be processed in the wrapper shell script, and the rest of the parameters, some of which may include spaces, are passed unchanged to the target process. The page documents two approaches: one for the situation when the command line argument processing and invocation of the target process command happen in the same function, and the second suitable for the situation when the processing is to be encapsulated in its own function. Naturally, the second is more complex, but suitable for libraries.

Same-Function Parameter Handling

The pattern uses a special separator character, that is injected between the arguments to be forwarded to the lower layer, followed by the recreation of the command line with set.

The pattern handles consistently both double-quote enclosed and single-quote encloses command line arguments that contain spaces.

# ...

local args
local separator=$'\x1f' # US - unit separator

while [[ -n $1 ]]; do

    if [[ $1 = "..." ]]; then

        #
        # process arguments that make sense at this layer
        #
        echo "processing $1 at this level ..."

        # ...

    else

        #
        # ... and accumulate the rest of the arguments, separated by the special separator character
        #
        [[ -z ${args} ]] && args="$1" || args="${args}${separator}$1"
    fi
    shift
done

#
# re-assemble the command line, by re-initializing the positional parameters, and pass it to the underlying process
#
IFS=${separator}
set - ${args}
IFS="$(printf ' \t\n')" # restore the standard separators

#
# Use "$@" built-in variable, which encloses each positional parameter in its own set of double quotes
#

java -cp ... io.novaordis.playground.Main "$@"

Note that the command can be debugged as follows:

...

local command_prefix="java -cp ... io.novaordis.playground.Main" 
debug ${command_prefix} "$@"
${command_prefix} "$@"

Dedicated Function Parameter Handling

The alternative is to encapsulate the parameter processing logic in a function, and restore the remaining parameters as positional parameters. The process-common-arguments() function in the example linked below extracts "common" arguments such as "--verbose", "-v", "help" or "--help" from the command line arguments and sets the appropriate global variables, while setting the remaining command line arguments as elements of a global array, which is converted to positional parameters with set -- "${ARGS[@]}":

process-common-arguments "$@" && set -- "${ARGS[@]}" || { echo "failed to process common arguments" 1>&2; exit 1; }

For more details and usage instructions, see:

process-common-arguments()