我想将流程的标准输出和标准错误重定向到单个文件。我在巴什怎么做?


当前回答

对于需要“管道”的情况,可以使用|&。

例如:

echo -ne "15\n100\n" | sort -c |& tee >sort_result.txt

or

TIMEFORMAT=%R;for i in `seq 1 20` ; do time kubectl get pods | grep node >>js.log ; done |& sort -h

这些基于Bash的解决方案可以分别处理标准输出和标准错误(从标准错误“sort-c”,或从标准错误到“sort-h”)。

其他回答

以下函数可用于自动切换stdout/stderr和日志文件之间的输出。

#!/bin/bash

    #set -x

    # global vars
    OUTPUTS_REDIRECTED="false"
    LOGFILE=/dev/stdout

    # "private" function used by redirect_outputs_to_logfile()
    function save_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
            exit 1;
        fi
        exec 3>&1
        exec 4>&2

        trap restore_standard_outputs EXIT
    }

    # Params: $1 => logfile to write to
    function redirect_outputs_to_logfile {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
            exit 1;
        fi
        LOGFILE=$1
        if [ -z "$LOGFILE" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"

        fi
        if [ ! -f $LOGFILE ]; then
            touch $LOGFILE
        fi
        if [ ! -f $LOGFILE ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
            exit 1
        fi

        save_standard_outputs

        exec 1>>${LOGFILE%.log}.log
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
    }

    # "private" function used by save_standard_outputs() 
    function restore_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"
            exit 1;
        fi
        exec 1>&-   #closes FD 1 (logfile)
        exec 2>&-   #closes FD 2 (logfile)
        exec 2>&4   #restore stderr
        exec 1>&3   #restore stdout

        OUTPUTS_REDIRECTED="false"
    }

脚本内部用法示例:

echo "this goes to stdout"
redirect_outputs_to_logfile /tmp/one.log
echo "this goes to logfile"
restore_standard_outputs 
echo "this goes to stdout"

看看这里。应该是:

yourcommand &> filename

它将标准输出和标准错误重定向到文件名。

简短回答:命令>文件名2>&1或命令>>文件名


说明:

考虑以下代码,该代码将单词“stdout”打印到stdout,将单词“tderror”打印到tderror。

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

注意,“&”操作符告诉bash 2是文件描述符(指向stderr),而不是文件名。如果省略了“&”,该命令将stdout打印到stdout,并创建一个名为“2”的文件,并在其中写入stderror。

通过尝试上面的代码,您可以亲眼看到重定向操作符是如何工作的。例如,通过更改两个描述符1、2中的哪个文件被重定向到/dev/null,以下两行代码分别从stdout和stderror中删除所有内容(打印剩余内容)。

$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout

现在,我们可以解释为什么以下代码不产生输出的解决方案:

(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1

为了真正理解这一点,我强烈建议您阅读有关文件描述符表的网页。假设你已经完成了阅读,我们可以继续。注意,Bash从左到右处理;因此,Bash首先看到>/dev/null(这与1>/dev/null相同),并将文件描述符1设置为指向/dev/null而不是stdout。完成此操作后,Bash向右移动,看到2>&1。这将文件描述符2设置为指向与文件描述符1相同的文件(而不是指向文件描述符1本身!!!!(有关详细信息,请参阅此指针资源))。由于文件描述符1指向/dev/null,文件描述符2指向与文件描述符1相同的文件,因此文件描述符2现在也指向/dev/null。因此,两个文件描述符都指向/dev/null,这就是为什么不呈现输出。


为了测试您是否真正理解这个概念,请尝试在切换重定向顺序时猜测输出:

(echo "stdout"; echo "stderror" >&2)  2>&1 >/dev/null

标准错误

这里的理由是,从左到右计算,Bash看到2>&1,因此将文件描述符2设置为指向与文件描述符1相同的位置,即stdout。然后,它将文件描述符1(记住>/dev/null=1>/dev/null)设置为指向>/dev/null,从而删除通常发送到标准输出的所有内容。因此,我们只剩下未发送到子shell中的stdout的代码(括号中的代码),即“stderror”。值得注意的是,尽管1只是指向stdout的指针,但通过2>&1将指针2重定向到1不会形成指针链2->1->stdout。如果这样做了,作为将1重定向到/dev/null的结果,代码2>&1>/dev/null将给出指针链2->1->/dev/null,因此代码将不会生成任何内容,与我们上面看到的相反。


最后,我要指出,有一种更简单的方法可以做到这一点:

从这里的第3.6.4节中,我们可以看到我们可以使用运算符&>来重定向stdout和stderr。因此,要将任何命令的stderr和stdout输出重定向到\dev\null(这会删除输出),只需键入$command&>/dev/null或者在我的例子中:

$ (echo "stdout"; echo "stderror" >&2) &>/dev/null

关键要点:

文件描述符的行为类似于指针(尽管文件描述符与文件指针不同)将文件描述符“a”重定向到指向文件“f”的文件描述符“b”,会导致文件描述符“a”指向与文件描述符b-file“f”相同的位置。它不会形成指针链a->b->f由于以上原因,顺序很重要,2>&1>/dev/null是!=>/dev/null 2>&1。一个生成输出,另一个不生成!


最后看看这些伟大的资源:

重定向的Bash文档,文件描述符表的解释,指针介绍

do_something 2>&1 | tee -a some_file

这会将标准错误重定向到标准输出,将标准输出重定向到some_file并将其打印到标准输出。

bash your_script.sh 1>file.log 2>&1

1> log指示shell将标准输出发送到file.log文件,2>&1告诉它将标准错误(文件描述符2)重定向到标准输出(文件描述符1)。

注意:正如liw.fi指出的那样,顺序很重要,2>&11>file.log不起作用。