假设我有一个像下面这样的脚本:

useless.sh

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

我有另一个shell脚本:

alsoUseless.sh

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

我想捕捉“这是错误”,或任何其他stderr从无用的。sh,到一个变量。 我们称它为ERROR。

注意,我使用了stdout。我想继续使用stdout,所以在这种情况下,将stderr重定向到stdout没有帮助。

所以,基本上,我想做

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

但这显然行不通。

我也知道我能做到

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

但这是丑陋和不必要的。

不幸的是,如果这里没有答案,这就是我要做的。

我希望还有别的办法。

有人有更好的主意吗?


当前回答

我是这样做的:

#
# $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-

它确实使用了一个临时文件。但至少丑陋的东西被包裹在一个函数中。

其他回答

这个问题有很多重复的地方,其中许多都有一个稍微简单的使用场景,您不希望同时捕获stderr、stdout和退出代码。

if result=$(useless.sh 2>&1); then
    stdout=$result
else
    rc=$?
    stderr=$result
fi

适用于常见的场景,在这种场景中,您希望在成功的情况下得到正确的输出,或者在失败的情况下在stderr上得到诊断消息。

注意,shell的控制语句已经检查了$?在引擎盖下;所以任何看起来像

cmd
if [ $? -eq 0 ], then ...

只是一种笨拙的,不常用的说法吗

if cmd; then ...

一个简单的解决方案

{ ERROR=$(./useless.sh 2>&1 1>&$out); } {out}>&1
echo "-"
echo $ERROR

会产生:

This Is Output
-
This Is Error

改进YellowApple的回答:

这是一个Bash函数,用于将stderr捕获到任何变量中

stderr_capture_example.sh:

#!/usr/bin/env bash

# Capture stderr from a command to a variable while maintaining stdout
# @Args:
# $1: The variable name to store the stderr output
# $2: Vararg command and arguments
# @Return:
# The Command's Returnn-Code or 2 if missing arguments
function capture_stderr {
  [ $# -lt 2 ] && return 2
  local stderr="$1"
  shift
  {
    printf -v "$stderr" '%s' "$({ "$@" 1>&3; } 2>&1)"
  } 3>&1
}

# Testing with a call to erroring ls
LANG=C capture_stderr my_stderr ls "$0" ''

printf '\nmy_stderr contains:\n%s' "$my_stderr"

测试:

bash stderr_capture_example.sh

输出:

 stderr_capture_example.sh

my_stderr contains:
ls: cannot access '': No such file or directory

此函数可用于捕获返回的对话框命令的选择。

重定向stderr到stdout, stdout到/dev/null,然后使用反勾号或$()捕获重定向的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}