在Bash中捕获stdout和stderr

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

  • 将stdout和stderr捕获到不同的变量中13个答案

  • 没有临时文件,无法捕获两者。

    您可以将stderr捕获到变量并将stdout传递到用户屏幕(从此处取样):

    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:

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


    在没有临时文件的情况下(如果您喜欢管道),使用流程替换, source和正确declare ,捕获stderrstdout方法非常糟糕。 我会打电话给你的命令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
    

    将通过stdout显示以前的内容。

    最后,我们使用流程替换来获取这些行的内容。


    你也提到了命令的返回码。 将banana

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

    我们还会在变量bret包含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)"
    

    所有这些都是安全的,因为我们唯一的sourceeval东西是从declare -p中获得的,并且总是会被正确地转义。


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

    例如:

    banana() {
        printf 'banana to stdout %dn' {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)
    

    你可以做:

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

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

    链接地址: http://www.djcxy.com/p/25605.html

    上一篇: Capture both stdout and stderr in Bash

    下一篇: What does the ampersand indicate in this bash command 1>&2