When writing a wrapper script, one often has to process the command line arguments to transform them according to his needs, to change some arguments, to remove or insert some, or perhaps to reorder them.

Naive approach

The naive approach to do that is¹:

# Process arguments, building a new argument list new_args="" for arg in "$@" do case "$arg" in --foobar) # Convert --foobar to the new syntax --foo=bar new_args="$args --foo=bar" ;; *) # Take other options as they are new_args="$args $arg" ;; esac done # Call the actual program exec program $new_args

This naive approach is simple, but fragile, as it will break on arguments that contain a space. For instance, calling wrapper --foobar "some file" (where some file is a single argument) will result in the call program --foo=bar some file (where some and file are two distinct arguments).

Correct approach

To handle spaces in arguments, we need either:

to quote them in the new argument list, but that requires escaping possible quotes they contain, which would be error-prone, and implies using external programs such as sed;

to use an actual list or array, which is a feature of advanced shells such as Bash or Zsh, not standard shell…

… except standard shell does support arrays, or rather, it does support one specific array: the positional parameter list "$@" ². This leads to one solution to process arguments in a reliable way, which consists in rebuilding the positional parameter list with the built-in command set -- :

# Process arguments, building a new argument list in "$@" # "$@" will need to be cleared, not right now but on first iteration only first_iter=1 for arg in "$@" do if [ "$first_iter" -eq 1 ] then # Clear the argument list set -- first_iter=0 fi case "$arg" in --foobar) set -- "$@" --foo=bar ;; *) set -- "$@" "$arg" ;; esac done # Call the actual program exec program "$@"

Notes