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 another shell script:
alsoUseless.sh
./useless.sh | sed 's/Output/Useless/'
I want to capture "This Is Error", or any other stderr from useless.sh, into a variable. Let's call it ERROR.
Notice that I am using stdout for something. I want to continue using stdout, so redirecting stderr into stdout is not helpful, in this case.
So, basically, I want to do
./useless.sh 2> $ERROR | ...
but that obviously doesn't work.
I also know that I could do
./useless.sh 2> /tmp/Error
ERROR=`cat /tmp/Error`
but that's ugly and unnecessary.
Unfortunately, if no answers turn up here that's what I'm going to have to do.
I'm hoping there's another way.
Anyone have any better ideas?
In zsh:
Capture AND Print stderr
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 oftee
will be captured by$()
rather than go to the console, but stderr(oftee
) will still go to the console so we use that as the second output fortee
via the special file/dev/fd/2
sincetee
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 oftee
at the end of the pipeline and the pipeline itself routes stdout of./useless.sh
to the stdin oftee
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.