Search code examples
shdefault-valuevariadic

shell: default values for varargs ($@)


So I'm writing a shell-script that takes optional arguments (parsing them with getopts and what not; but that doesn't really matter here).

The user (of the script) is supposed to pass some paths as arguments, which are then processed by some workhorse utilitiy. Of course the paths may contain spaces, so I'm passing the args on with double-quotes ("$@"), along with numerous other flags:

something like this:

workhorse        \
  --verbose      \
  --stats        \
  --one-flag     \
  --another-flag \
  "$@"

Everything works nicely, but then:

If the user did not specify any paths, I would like to fall back to some default values. I have no idea how to achieve this while still be able to handle spaces and what not.

the naive approach would be something like:

if [ $# -gt 0 ]; then
  workhorse        \
    --verbose      \
    --stats        \
    --one-flag     \
    --another-flag \
    "$@"
else
  workhorse        \
    --verbose      \
    --stats        \
    --one-flag     \
    --another-flag \
    /home/foo /home/bar
fi

But that of course is very ugly. Instead, I would like to use variable substitution, to replace the $@ with default values, like so:

default_paths="/home/foo /home/bar"
workhorse        \
  --verbose      \
  --stats        \
  --one-flag     \
  --another-flag \
  ${@:-${default_paths}}

This works, as long as the paths passed via the cmdline do not contain any whitespace (no double quotes around $@). To support whitespaces in the args, I would use double-quote but "${@:-${default_paths}" will (while correctly expanding the cmdline-args) pass the /home/foo /home/bar string as a single argument to my workhorse.

I could simplify my "ugly" solution above (that just calls the workhorse differently, depending on whether there are any cmdline-provided paths or nor), by putting the flags into a $flags variable - but what if those flags could contain (paths with) spaces themselves?

So: is there a way to provide default values for variadic shell arguments that can contain spaces?

Something like the inverse of shift might help (where you push new arguments to positional parameters queue)

I'm looking for a POSIX-compliant solution (rather than bash-arrays).


Solution

  • If you have control over how default_paths gets set in your script, then you can just use set to assign the paths as positional arguments

    if [ $# -eq 0 ]; then
      set -- "/home/foo" "/home/bar" "/home/path with spaces"
    fi
    

    and continue using "$@" as the arguments list.