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 "$@"
4 comments
wednesday 08 june 2016 à 14:37 Loïc Minier said : #1
wednesday 08 june 2016 à 15:21 Tanguy said : #2
thursday 09 june 2016 à 09:55 martin said : #3
thursday 09 june 2016 à 10:36 Tanguy said : #4