捕捉猛砸标准输出和标准错误[复制](Capture both stdout and stderr i

2019-06-21 21:26发布

这个问题已经在这里有一个答案:

  • 捕获输出和错误到不同的变量 13个回答

我知道这句法

var=`myscript.sh`

要么

var=$(myscript.sh)

将捕捉到的结果( stdout的) myscript.shvar 。 我可以重定向stderrstdout ,如果我想同时捕获。 如何他们每个人保存到不同的变量?

我在这里的使用情况是,如果返回代码为非零我想呼应stderr和抑制其他。 可能还有其他方法可以做到这一点,但这种做法似乎它会工作,如果它实际上是可能的。

Answer 1:

有没有办法不用临时文件,以同时捕获。

您可以捕获标准错误变量和(从样品通过标准输出到用户屏幕在这里 ):

exec 3>&1                    # Save the place that stdout (1) points to.
output=$(command 2>&1 1>&3)  # Run command.  stderr is captured.
exec 3>&-                    # Close FD #3.

# Or this alternative, which captures stderr, letting stdout through:
{ output=$(command 2>&1 1>&3-) ;} 3>&1

但是没有办法同时捕获输出和错误:

什么,你不能做的是一个变量捕获stdout和stderr在另一个,只用FD重定向。 必须使用一个临时文件(或命名管道)来实现的那一个。



Answer 2:

有一个非常丑陋的方式来捕捉stderrstdout中没有临时文件两个单独的参数(如果你喜欢管道),使用过程中替换 , source ,并declare恰当。 我会打电话给你的命令banana 。 你可以模仿与函数这样的命令:

banana() {
    echo "banana to stdout"
    echo >&2 "banana to stderr"
}

我假设你想要的标准输出banana变量bout和标准误差banana变量berr 。 下面是(仅Bash≥4)将实现这一神奇的:

. <({ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)

因此,这里发生了什么?

让我们从最开始的术语:

bout=$(banana)

这仅仅是分配给标准的方式bout的标准输出banana ,显示在终端上的标准误差。

然后:

{ bout=$(banana); } 2>&1

将仍然分配给bout的标准输出banana ,但标准错误banana经由标准输出显示在终端(由于重定向2>&1

然后:

{ bout=$(banana); } 2>&1; declare -p bout >&2

将做如上述,但也将在终端显示(通过stderr)上的内容boutdeclare内置:这将很快重新使用。

然后:

berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr

将要分配给berr的stderr的banana和显示的内容berrdeclare

在这一点上,你有你的终端屏幕上:

declare -- bout="banana to stdout"
declare -- berr="banana to stderr"

与线

declare -- bout="banana to stdout"

通过stderr被显示。

最后重定向:

{ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1

将通过标准输出显示前面。

最后,我们使用一个进程替换到这些行的内容。


你提到的命令的返回码了。 更改banana到:

banana() {
    echo "banana to stdout"
    echo >&2 "banana to stderr"
    return 42
}

我们还必须返回代码banana在变量bret像这样:

. <({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)

您可以在不采购和使用过程中替换做eval太(它使用bash <4太作品):

eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"

而这一切是安全的,因为只有东西我们是source ING或eval从获得ING declare -p而且将永远是正确转义。


当然,如果你想在一个阵列的输出(例如, mapfile ,如果你使用Bash≥4,否则更换mapfilewhile - read圈),适应很简单。

例如:

banana() {
    printf 'banana to stdout %d\n' {1..10}
    echo >&2 'banana to stderr'
    return 42
}

. <({ berr=$({ mapfile -t bout < <(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)

并返回代码:

. <({ berr=$({ mapfile -t bout< <(banana; bret=$?; declare -p bret >&3); } 3>&2 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)


Answer 3:

你可以做:

OUT=$(myscript.sh 2> errFile)
ERR=$(<errFile)

现在$OUT将有脚本的标准输出和$ERR有脚本的错误输出。



Answer 4:

一个简单的,但不是优雅的方式:stderr重定向到一个临时文件,然后读出来:

TMP=$(mktemp)
var=$(myscript.sh 2> "$TMP")
err=$(cat "$TMP")
rm "$TMP"


Answer 5:

虽然我还没有找到一种方法来捕获stderr和标准输出到在bash独立变量,我同时发送给使用同一个变量...

result=$( { grep "JUNK" ./junk.txt; } 2>&1 )

...然后我检查退出状态“$?”,并在$结果的数据采取适当的行动。



Answer 6:

# NAME
#   capture - capture the stdout and stderr output of a command
# SYNOPSIS
#   capture <result> <error> <command>
# DESCRIPTION
#   This shell function captures the stdout and stderr output of <command> in
#   the shell variables <result> and <error>.
# ARGUMENTS
#   <result>  - the name of the shell variable to capture stdout
#   <error>   - the name of the shell variable to capture stderr
#   <command> - the command to execute
# ENVIRONMENT
#   The following variables are mdified in the caller's context:
#    - <result>
#    - <error>
# RESULT
#   Retuns the exit code of <command>.
# SOURCE
capture ()
{
    # Name of shell variable to capture the stdout of command.
    result=$1
    shift

    # Name of shell variable to capture the stderr of command.
    error=$1
    shift

    # Local AWK program to extract the error, the result, and the exit code
    # parts of the captured output of command.
    local evaloutput='
        {
            output [NR] = $0
        }
        END \
        {
            firstresultline = NR - output [NR - 1] - 1
            if (Var == "error") \
            {
                for (i = 1; i < firstresultline; ++ i)
                {
                    printf ("%s\n", output [i])
                }
            }
            else if (Var == "result") \
            {
                for (i = firstresultline; i < NR - 1; ++ i)
                {
                    printf ("%s\n", output [i])
                }
            }
            else \
            {
                printf ("%d", output [NR])
            }
        }'

    # Capture the stderr and stdout output of command, as well as its exit code.
    local output="$(
    {
        local stdout
        stdout="$($*)"
        local exitcode=$?
        printf "\n%s\n%d\n%d\n" \
               "$stdout" "$(echo "$stdout" | wc -l)" "$exitcode"
    } 2>&1)"

    # extract the stderr, the stdout, and the exit code parts of the captured
    # output of command.
    printf -v $error "%s" \
                     "$(echo "$output" | gawk -v Var="error" "$evaloutput")"
    printf -v $result "%s" \
                      "$(echo "$output" | gawk -v Var="result" "$evaloutput")"
    return $(echo "$output" | gawk "$evaloutput")
}


文章来源: Capture both stdout and stderr in Bash [duplicate]