Reputation: 33
I have a script I use for building my kernel, and in it I have a function I want to use to catch errors in my build commands, but I can't figure out how to pass multiple arguments as one to get it working properly. The syntax is as follows:
run_build() {
cmd=$($1)
status=${PIPESTATUS[0]}
$*
if ($status != 0); then
echo "$cmd failed!"
exit 1
else
echo "$cmd succeeded."
fi
}
The problem is, when I try to pass a make
command with its arguments, the make
command is being executed with no arguments. I tried to use the "$*" syntax to call all arguments but it doesn't seem to work. An example command would be
make O=out -j8 zImage
I need the next 3 arguments to be included when calling the line from the script. Anyone have ideas?
Upvotes: 1
Views: 1422
Reputation: 15246
Not fond of this setup for a few obvious reasons and few less obvious.
For the record, c.f. this page on why not to do this.
Also worthy of note, in case you shift to eval
, which idealogically is kind of what this function is doing... please read this too.
...but for a simplistic solution -
Arguments come in as an array. If you are running the build, then make your function run the build, with quoted arguments.
run_build() {
if make "$@" # QUOTED, *explicit* call to make
then echo "'make $@' succeeded."
else echo "'make $@' failed."
return 1 # exit in function only sets return - be explicit
fi
}
run_build O=out -j8 zImage # run_build as a make synonym
Don't try to build do-anything functions.
That way lies madness.
If you must use other commands than make, then validate and verify.
run_build() {
local cmd=$1
shift
case "$cmd" in
make|or|some|other|specifically|ok|word)
if "$cmd" "$@" # QUOTED!!!
then echo "'$cmd $@' succeeded."
else echo "'$cmd $@' failed."
return 1
fi
;;
*) echo "Invalid argument: '$cmd' not recognized."
return 1
;;
esac
}
If you aren't at least doing that, what's the purpose of the function? I mean, you are passing in all the parts of the command anyway, and not doing much with them beside executing them. Why not just...you know, execute them, instead of bothering with a function? But even if you keep it to it's simplest, quote, quote, quote.
run_build() { "$@" && echo "'$@' succeeded" || {
echo "'$@'failed; return 1; }; }
Upvotes: 1
Reputation: 189317
The proper solution to this is probably something like
if "$@"; then
echo "$@ succeeded" >&2
else
rc=$?
echo "$@ failed" >&2
fi
but this still seems like you are replacing perfectly good built-in functionality with something worse.
Upvotes: 1
Reputation: 246744
First point, you don't want to pass the entire command as a single argument: I'm trying to put a command in a variable, but the complex cases always fail!
This is the main error: cmd=$($1)
-- the $()
syntax invokes Command Substitution that executes the first argument. Just use cmd=$1
to store the first parameter into the "cmd" variable.
Additional errors:
if ($status != 0); then
-- that syntax is incorrect: use if ((status != 0)); then
for proper arithmetic evaluation.$*
-- to execute the positional parameters correctly, use "$@"
(with the quotes) -- that form will maintain any arguments that contain whitespace as intended.Upvotes: 0