Maintaining The "$@" Interface
If you want shell syntax (compound commands, redirections, etc), you need to invoke a shell. Thus:
./script.sh bash -c 'ls && clear'
...you'll also need to change $@
to "$@"
(unquoted, $@
is exactly the same as -- meaning, has all the bugs of -- $*
).
If you want to pass data, do so with extra arguments out-of-band from your code to avoid security bugs:
dir=/tmp # but unlike eval, this is still safe with *any* directory name
./script.sh bash -c 'ls "$1" && clear' _ "$dir"
Unlike some other approaches, this still lets ./script.sh printf '%s\n' "first line" "second line"
work.
Accepting Only One Argument
Using "$@"
promises to the user that multiple arguments will be processed; however, eval "$*"
, like bash -c "$*"
, discards distinctions between those arguments, whereas bash -c "$@"
silently ignores arguments past the first unless the first argument is written with knowledge of that calling convention.
To only accept one argument, and parse it as code, use:
eval "$1"
To only accept the first argument as code, and keep subsequent arguments as $1
, $2
, etc. in the context of that code, use:
code=$1; shift; eval "$code"