在Bash中redirectstderr和stdout

我想将进程的stdout和stderrredirect到单个文件。 我如何在Bash中做到这一点?

看看这里 。 应该:

yourcommand &>filename 

(将stdoutstderrredirect到文件名)。

 do_something 2>&1 | tee -a some_file 

这将把stderrredirect到标准输出和标准输出到some_file 并将其输出到标准输出。

你可以将stderrredirect到stdoutstdout到一个文件中:

 some_command >file.log 2>&1 

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

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

 # 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。 用于守护进程。

对原帖的作者,

这取决于你需要达到什么。 如果您只是需要redirect到/从您的脚本调用的命令,答案已经给出。 Mine是关于当前脚本中redirect的它会影响所提到的代码片段之后的所有命令/内置函数(包括分支)。


另一个很酷的解决scheme是将redirect到std-err / out和logging器或日志文件,这涉及到将“stream”分成两部分。 这个function由'tee'命令提供,它可以一次写入/追加到多个文件描述符(文件,套接字,pipe道等):tee FILE1 FILE2 …>(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)的terminal。 在实践中,它可能是一个pipe道,sockets或其他任何东西。

  • 创buildFD#3和#4并分别指向与#1和#2相同的“位置”。 从现在起,更改FD#1不会影响FD#3。 现在FD#3和#4分别指向STDOUT和STDERR。 这些将被用作真正的terminalSTDOUT和STDERR。
  • 1>>(…)将STDOUTredirect到parens中的命令
  • parens(sub-shell)从exec的STDOUT(pipe)执行'tee'读取,并通过另一个pipe道redirect到'logger'命令到parens的子shell。 同时它将相同的input复制到FD#3(terminal)
  • 第二部分,非常相似,是关于对STDERR和FD#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 

如果你想看到更清晰的图片,将这两行添加到脚本中:

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

1>file.log指示shell将STDOUT发送到文件file.log2>&1告诉它将STDERR(文件描述符2)redirect到STDOUT(文件描述符1)。

注:命令如liw.fi所指出的, 2>&1 1>file.log file.log不起作用。

奇怪的是,这个工程:

 yourcommand &> filename 

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

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

你必须使用:

 yourcommand 1>> filename 2>&1 
 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&stderr写入syslog。

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

我想要一个解决scheme,将stdout和stderr的输出写入日志文件,而stderr仍然在控制台上。 所以我需要通过tee复制stderr输出。

这是我find的解决scheme:

 command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile 
  • 首先交换stderr和stdout
  • 然后将stdout附加到日志文件
  • pipe道stderr开球,并将其追加到日志文件

对于tcsh,我必须使用下面的命令:

 command >& file 

如果使用command &> file ,则会给出“无效的空命令”错误。

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