Let\'s say I have a script like the following:
useless.sh
echo \"This Is Error\" 1>&2
echo \"This Is Output\"
And I have an
Capture AND Print stderr
ERROR=$( ./useless.sh 3>&1 1>&2 2>&3 | tee /dev/fd/2 )
Breakdown
You can use $() to capture stdout, but you want to capture stderr instead. So you swap stdout and stderr. Using fd 3 as the temporary storage in the standard swap algorithm.
If you want to capture AND print use tee to make a duplicate. In this case the output of tee will be captured by $() rather than go to the console, but stderr(of tee) will still go to the console so we use that as the second output for tee via the special file /dev/fd/2 since tee expects a file path rather than a fd number.
NOTE: That is an awful lot of redirections in a single line and the order matters. $() is grabbing the stdout of tee at the end of the pipeline and the pipeline itself routes stdout of ./useless.sh to the stdin of tee AFTER we swapped stdin and stdout for ./useless.sh.
Using stdout of ./useless.sh
The OP said he still wanted to use (not just print) stdout, like ./useless.sh | sed 's/Output/Useless/'.
No problem just do it BEFORE swapping stdout and stderr. I recommend moving it into a function or file (also-useless.sh) and calling that in place of ./useless.sh in the line above.
However, if you want to CAPTURE stdout AND stderr, then I think you have to fall back on temporary files because $() will only do one at a time and it makes a subshell from which you cannot return variables.