如何将标准错误存储在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 )