How to store standard error in a variable in a Bas

2018-12-31 23:59发布

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?

14条回答
不再属于我。
2楼-- · 2019-01-01 01:02

In zsh:

{ . ./useless.sh > /dev/tty } 2>&1 | read ERROR
$ echo $ERROR
( your message )
查看更多
几人难应
3楼-- · 2019-01-01 01:04

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.

查看更多
登录 后发表回答