我想向两stdout and stderr过程的一个单一的文件。我该怎么做,在庆典?

有帮助吗?

解决方案

看看这里。应该是:

yourcommand &>filename

(重定向既stdoutstderr到文件名)。

其他提示

do_something 2>&1 | tee -a some_file

这将会把stderr重定向到stdout和stdout到some_file 它打印到标准输出。

可以重定向 stderr的标准输出标准输出到一个文件:

some_command >file.log 2>&1 

请参阅 http://tldp.org/LDP/abs/html/io -redirection.html

此格式是优选的比最流行&>格式,只有在bash工作。在Bourne Shell中它可以被解释为在后台运行的命令。也格式是更具有可读性2(是STDERR)重定向到1(STDOUT)。

编辑:改变的顺序如在评论中指出

# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-

# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE

# Redirect STDERR to STDOUT
exec 2>&1

echo "This line will appear in $LOG_FILE, not 'on screen'"

现在,简单的回声将写信给$LOG_FILE.用于daemonizing.

来文提交人原来的岗位,

这取决于你需要什么来实现。如果你只是需要重新定向的一个命令你打电话从你的脚本,这些问题的答案都已经定。地雷是有关重定向 前脚本,影响到所有的命令/建件程序(包括福克斯之后)在提到代码段。


另一个很酷的解决方案是有关重定向到两std-err/出并记录或登录文件在一旦其中涉及分裂"一流"变成两个。这一功能是由't'的命令,这可以写/追加的几个文件的描述(文件,插座、管道,等等):tee1文件2...>(cmd1)>(cmd2)...

exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT


get_pids_of_ppid() {
    local ppid="$1"

    RETVAL=''
    local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
    RETVAL="$pids"
}


# Needed to kill processes running in background
cleanup() {
    local current_pid element
    local pids=( "$$" )

    running_pids=("${pids[@]}")

    while :; do
        current_pid="${running_pids[0]}"
        [ -z "$current_pid" ] && break

        running_pids=("${running_pids[@]:1}")
        get_pids_of_ppid $current_pid
        local new_pids="$RETVAL"
        [ -z "$new_pids" ] && continue

        for element in $new_pids; do
            running_pids+=("$element")
            pids=("$element" "${pids[@]}")
        done
    done

    kill ${pids[@]} 2>/dev/null
}

因此,从一开始。让我们假设,我们的终端连接/dev/stdout(FD#1)和/dev/stderr(FD#2).在实践中,这可能是一个管、套或者什么的。

  • 创建防卫和安全部队#3和第4点来相同的"位置"为1和2分别。改变FD#1不影响FD#3。现在,科特迪瓦国防安全部队#3和第4点来STDOUT and STDERR分别。这些将作为 真的 终端STDOUT and STDERR。
  • 1>>(...)重定向STDOUT到命令在括号
  • 括号(子壳)执行't'读exec的STDOUT(pipe)和重定向到'记录器'的命令通过另一个管子壳在括号.同时,它的副本相同的输入到FD#3(终端)
  • 第二部分,非常类似,大约是做同样的把戏STDERR和科特迪瓦国防安全部队#2和#4。

结果运行的一个脚本具有上述行和此外,这一:

echo "Will end up in STDOUT(terminal) and /var/log/messages"

...如下:

$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages

$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages

如果你想看到更清晰的画面,添加这些2条的脚本:

ls -l /proc/self/fd/
ps xf
bash your_script.sh 1>file.log 2>&1

1>file.log指示壳发送STDOUT到文件file.log,和2>&1告诉它STDERR(文件描述符2)重定向到STDOUT(文件描述符1)。

注意:的顺序事项liw.fi指出,2>&1 1>file.log不起作用

奇怪的是,工作的:

yourcommand &> filename

但是,这给出了一个语法错误:

yourcommand &>> filename
syntax error near unexpected token `>'

您必须使用:

yourcommand 1>> filename 2>&1

简短的回答: Command >filename 2>&1Command &>filename


说明:

考虑下列代码打印的字"stdout"to stdout和单词"stderror"以stderror.

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

注意,'&'操作员会告诉bash,2个文件描述(其中指stderr)并不是一个文件的名称。如果我们留下了'&',这种命令将打印 stdout 到stdout,并创建一个文件命名为"2"写 stderror 那里。

通过试用上述代码,你可以看到自己究竟如何向经营者的工作。例如,通过改变其文件的两个描述 1,2, 是重新定向到 /dev/null 以下两个代码行的删除标准输出,以及一切从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看到 >/dev/null 第(这是相同的 1>/dev/null),并设置文件的描述符1点至/dev/null而不是stdout。具有这样做,庆典,然后向右移动和看到 2>&1.这套文件描述2 指向同一文件 作为文件描述符1(不以文件描述符1本身!!!!(见 这个资源上的指针 更多信息)).由于文件描述符1点/dev/null和文件描述符2点到同一文件作为文件描述符1、文件描述符2现在还有点/dev/null。因此,这两个文件的描述符点/dev/null,并且这就是为什么没有输出渲染。


测试,如果你真的了解的概念,试图猜测输出,当我们开关的重新定向的顺序:

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

stderror

其理由是,评估从左到右,Bash看到2>&1,因而把该文件描述符2点到同一个地方文件的描述符1,即stdout。它然后将文件描述符1(记得>/dev/null=1>/dev/null)要点,以>/dev/null,因此删除一切,它通常会被送到到的标准。因此,我们所留下的是,这并不是发送给stdout在子shell(代码在括号内)-即"stderror".有趣的事要注意的是,即使1仅仅是一个指向标准输出,重新定向的指针2,1通过 2>&1 不会形成的链条的指针2->1->stdout。如果它这样做的结果向1/dev/null,代码 2>&1 >/dev/null 会得到的指链2->1->/dev/null,因此该守则将产生什么,相反,我们看到了什么上面。


最后,我注意到,有一个简单的方法来这样做:

从部分3.6.4 在这里,, 我们看到,我们可以使用的操作者 &> 重定向这两个stdout and stderr。因此,向这两个stderr和stdout输出的任何命令 \dev\null (删除的产出),我们简单的类型 $ command &> /dev/null 或者在我的例子:

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

要点:

  • 文件描述行为类似的指针(虽然文件的描述不同文件指针)
  • 重新定向的一个文件,描述符"a"到一个文件,描述符"b",这点文件"f",导致文件,描述符"a"指向同一个地方作为文件描述的b-文件"f"。它不会形成的链条的指针一->b>f
  • 由于上述,订单的事项, 2>&1 >/dev/null 是!= >/dev/null 2>&1.一个产生输出和其他不!

最后看一看这些巨大的资源:

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

LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"

exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )

它涉及:写STDOUT&标准错误到syslog

它几乎工作,但不能从xinted;(

我想要一个解决有的输出stdout加stderr写入记录文件和stderr仍然在控制台。所以我需要重复的stderr输出通过开球。

这是解决我发现:

command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
  • 第一次交换stderr和stdout
  • 然后追加的stdout日志文件
  • 管stderr开球的和追加它也记录文件

有关的情况下,当“管道”是必要可以使用:

  

<强> |&

例如:

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

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

此基于bash的解决方案可以通过管道STDOUT和STDERR分开(从 “排序-c” STDERR或从STDERR为 “sort -h”)。

(仅bash4) “最简单” 的方式:ls * 2>&- 1>&-

The following functions can be used to automate the process of toggling outputs beetwen stdout/stderr and a logfile.

#!/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"
    }

Example of usage inside script:

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"

For tcsh, I have to use the following command :

command >& file

If use command &> file , it will give "Invalid null command" error.

@fernando-fabreti

Adding to what you did I changed the functions slightly and removed the &- closing and it worked for me.

    function saveStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        exec 3>&1
        exec 4>&2
        trap restoreStandardOutputs EXIT
      else
          echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
          exit 1;
      fi
  }

  # Params: $1 => logfile to write to
  function redirectOutputsToLogfile {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        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
        saveStandardOutputs
        exec 1>>${LOGFILE}
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
      else
        echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
          exit 1;
      fi
  }
  function restoreStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
      exec 1>&3   #restore stdout
      exec 2>&4   #restore stderr
      OUTPUTS_REDIRECTED="false"
     fi
  }
  LOGFILE_NAME="tmp/one.log"
  OUTPUTS_REDIRECTED="false"

  echo "this goes to stdout"
  redirectOutputsToLogfile $LOGFILE_NAME
  echo "this goes to logfile"
  echo "${LOGFILE_NAME}"
  restoreStandardOutputs 
  echo "After restore this goes to stdout"

In situations when you consider using things like exec 2>&1 I find easier to read if possible rewriting code using bash functions like this:

function myfunc(){
  [...]
}

myfunc &>mylog.log
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top