If you have the full shell syntax available to you, then you can use
if, which does not appear as a failure to the shell:
if (eval "$cmd"); then
: # do nothing, it worked
printf 'Command %s failed with code %d\n' "$cmd" $?
Note that you can't use the more obvious
if ! eval… syntax, as the negation will hide the exit code. The "do nothing" bit there is there because shell syntax requires a then block with a command in it; you can't omit it or leave it empty.
The important thing is that an
if is not a failure to the shell, even though the evaluated command failed.
The parentheses are to run the command in a sub-shell; this prevents the command from e.g., setting variables that affect your script or doing something like
exit 1 to kill your script entirely.
Finally, note how I've used
eval instead of unquoted
$cmd. That's because unquoted command does word splitting in a way you probably don't expect. If you had
cmd='rm -Rf "foo * baz"', then when you run
$cmd what you're actually running is
rm -Rf \"foo * baz\" — which will expand the
* to all files in the directory, deleting everything (in addition to the two files
baz"). That's three arguments to
rm, before glob expansion, not the one you expected.
eval will apply the normal shell command parsing, I think leading to fewer surprises. There are other approaches (using arrays, for example) that are safer if this is a command being built up inside your script and not, e.g., a line read from a text file.