Você pode usar set -o pipefail
para obter o erro da parte anterior do pipeline:
The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.
$ foo() { [[ "$1" = 1 ]] || return 1; echo "hello world"; }
$ a=$(set -o pipefail; foo 2 | awk '{print $1}' || echo "fail..." >&2)
fail...
Mas, na verdade, não vejo por que atribuir duas vezes seria um problema. Em essência, você apenas modifica o valor que obteve se o comando for bem-sucedido ou o ignora se ele falhar.
Além disso, você pode condensar essa lógica um pouco:
if a=$(foo 1); then
a=${a%% *};
echo "first word of a is '$a'";
# do some work with $a...
else
echo "error..." >&2;
fi
imprime
first word of a is 'hello'