f() {
echo "command: $@"
$@
}
In general, you should use "$@"
, here, too, for the usual reasons.
But you're right, running a command like that doesn't process shell operators, be it redirections or stuff like &&
. You could change the function to eval
the command it gets, which would process redirections, but also everything else.
In particular, passing arbitrary filenames would become difficult again. E.g. this would end up running ls
on the two files foo
and bar
:
run_with_eval() {
eval "$@"
}
file='foo bar'
run_with_eval ls -l "$file"
You'd have to arrange for the filename to be passed quoted for the shell, which is somewhat awkward and error-prone.
But if you only want redirection, and even better, only output redirection with >
, you could have the function handle it manually:
#!/bin/bash
run_with_redir() {
local redir=
if [[ $1 = '>' ]]; then
redir=$2
shift 2
fi
## whatever else you do
if [[ $redir ]]; then
"$@" > "$redir"
else
"$@"
fi
}
run_with_redir echo "normal command, no redirection"
run_with_redir ">" output.txt echo "this gets redirected to output.txt"
That is, invoking the function with >
and a filename as the first two arguments runs the rest as a command with the output redirected. Without the >
, it runs the command normally. Note that the ">"
must be quoted when calling the function, otherwise we'd again get the output of the whole function redirected. Expanding that to support e.g. >>
should be straightforward, even if repetitive.
That should also work in the trickier cases:
run_with_redir ">" "output file with space.txt" ls -l "other file with space"
eval
and running another full shell aren't that different. In both cases there's a full round of shell expansions etc. done. Of course, aneval
happens in the same shell environment, while starting another shell starts another environment. But all the quoting complications and issues with files called$(reboot)
are there. Also, here, you probably should usebash -c "$*"
because-c
only takes one argument. Note e.g. how thef echo a-one a-two
only prints an empty line with function here. – ilkkachu Apr 14 '21 at 19:58