如何将标准错误存储在Bash脚本的variables中

假设我有如下的脚本:

useless.sh

echo "This Is Error" 1>&2 echo "This Is Output" 

我有另一个shell脚本:

alsoUseless.sh

 ./useless.sh | sed 's/Output/Useless/' 

我想捕获“这是错误”,或从useless.sh中的任何其他标准错误,变成一个variables。 我们称之为错误。

请注意,我正在使用stdout的东西。 我想继续使用stdout,因此在这种情况下,将stderrredirect到stdout是没有用的。

所以,基本上,我想要做的

 ./useless.sh 2> $ERROR | ... 

但是这显然不起作用。

我也知道我能做到

 ./useless.sh 2> /tmp/Error ERROR=`cat /tmp/Error` 

但这是丑陋的和不必要的。

不幸的是,如果没有答案出现在这里,我将不得不做的。

我希望有另一种方式。

任何人有更好的想法?

捕获错误文件将会更加简单:

 ERROR=$(</tmp/Error) 

shell认识到这一点,不必运行“ cat ”来获取数据。

更大的问题是困难的。 我不认为有一个简单的方法来做到这一点。 您必须将整个pipe道构build到子shell中,最终将其最终标准输出发送到文件,以便将错误redirect到标准输出。

 ERROR=$( { ./useless.sh | sed s/Output/Useless/ > outfile; } 2>&1 ) 

请注意,分号是必要的(在经典的贝壳 – Bourne,Korn–当然,也可能在Bash中)。 “ {} ”对所包含的命令进行I / Oredirect。 正如所写的,它也会捕获sed错误。

(正式未经testing的代码 – 使用风险自负。)

alsoUseless.sh

这将允许您通过诸如sed的命令来pipe理您的useless.sh脚本的输出,并将stderr保存在一个名为error的variables中。 pipe道的结果被发送到stdout显示或被传送到另一个命令。

它设置了一些额外的文件描述符来pipe理所需的redirect。

 #!/bin/bash exec 3>&1 4>&2 #set up extra file descriptors error=$( { ./useless.sh | sed 's/Output/Useless/' 2>&4 1>&3; } 2>&1 ) echo "The message is \"${error}.\"" exec 3>&- 4>&- # release the extra file descriptors 

将stderrredirect到stdout,将stdoutredirect到/ dev / null,然后使用反引号或$()来捕获redirect的stderr:

 ERROR=$(./useless.sh 2>&1 >/dev/null) 
 # command receives its input from stdin. # command sends its output to stdout. exec 3>&1 stderr="$(command </dev/stdin 2>&1 1>&3)" exitcode="${?}" echo "STDERR: $stderr" exit ${exitcode} 
 $ b=$( ( a=$( (echo stdout;echo stderr >&2) ) ) 2>&1 ) $ echo "a=>$ab=>$b" a=>stdout b=>stderr 

以下是我如何做到的:

 # # $1 - name of the (global) variable where the contents of stderr will be stored # $2 - command to be executed # captureStderr() { local tmpFile=$(mktemp) $2 2> $tmpFile eval "$1=$(< $tmpFile)" rm $tmpFile } 

用法示例:

 captureStderr err "./useless.sh" echo -$err- 

确实使用临时文件。 但至less丑陋的东西是包装在一个函数。

这是一个有趣的问题,我希望有一个优雅的解决scheme。 可悲的是,我最终得到了一个和Leffler先生类似的解决scheme,但是我会补充一点,你可以在Bash函数中调用无用的方法来提高可读性:

 #!/斌/庆典

函数无用{
     /tmp/useless.sh |  sed's / Output / Useless /'
 }

 ERROR = $(没用)
 echo $ ERROR

所有其他types的输出redirect必须由临时文件支持。

这篇文章帮助我为自己的目的提出了一个类似的解决scheme:

 MESSAGE=`{ echo $ERROR_MESSAGE | format_logs.py --level=ERROR; } 2>&1` 

那么只要我们的MESSAGE不是一个空string,我们就把它传递给其他的东西。 这将让我们知道,如果我们的format_logs.py失败了某种pythonexception。

如果你想绕过临时文件的使用,你可以使用进程replace。 我还没有完全得到它的工作。 这是我第一次尝试:

 $ .useless.sh 2> >( ERROR=$(<) ) -bash: command substitution: line 42: syntax error near unexpected token `)' -bash: command substitution: line 42: `<)' 

然后我试了一下

 $ ./useless.sh 2> >( ERROR=$( cat <() ) ) This Is Output $ echo $ERROR # $ERROR is empty 

然而

 $ ./useless.sh 2> >( cat <() > asdf.txt ) This Is Output $ cat asdf.txt This Is Error 

所以进程replace通常是正确的…不幸的是,每当我用$()中的某个东西包装STDIN的时候,试图把它捕获到一个variables中,我就失去了$()的内容。 我认为这是因为$()启动了一个subprocess,它不再有权访问父进程拥有的/ dev / fd中的文件描述符。

stream程replace让我有能力处理不再在STDERR中的数据stream,很不幸,我似乎无法按照自己想要的方式来操作它。

在zsh:

 { . ./useless.sh > /dev/tty } 2>&1 | read ERROR $ echo $ERROR ( your message )