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