linux shell 屏幕显示stdout stderr的同时 分别重定向到文件

转载 2013年12月04日 22:40:50

I'm assuming you want to still see STDERR and STDOUT on the terminal. You could go for Josh Kelley's answer, but I find keeping a tail around in the background which outputs your log file very hackish and cludgy. Notice how you need to keep an exra FD and do cleanup afterward by killing it and technically should be doing that in a trap '...' EXIT.

There is a better way to do this, and you've already discovered it: tee.

Only, instead of just using it for your stdout, have a tee for stdout and one for stderr. How will you accomplish this? Process substitution and file redirection:

command > >(tee stdout.log) 2> >(tee stderr.log >&2)

Let's split it up and explain:

> >(..)

>(...) (process substitution) creates a FIFO and lets tee listen on it. Then, it uses > (file redirection) to redirect the STDOUT of command to the FIFO that your first tee is listening on.

Same thing for the second:

2> >(tee stderr.log >&2)

We use process substitution again to make a tee process that reads from STDIN and dumps it intostderr.logtee outputs its input back on STDOUT, but since its input is our STDERR, we want to redirect tee's STDOUT to our STDERR again. Then we use file redirection to redirect command's STDERR to the FIFO's input (tee's STDIN).


Process substitution is one of those really lovely things you get as a bonus of choosing bash as your shell as opposed to sh (POSIX or Bourne).

In sh, you'd have to do things manually:

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee stdout.log < "$out" &
tee stderr.log < "$err" >&2 &
command >"$out" 2>"$err"

6. Miscellaneous Operators

Aside from the standard I/O operators, bash also provides a few more advanced operators that make life on the shell that much nicer.

6.1. Process Substitution

A cousin of the pipe is the process substitution operator, which comes in two forms: <() and >(). It's a convenient way to use named pipes without having to create temporary files. Whenever you think you need a temporary file to do something, process substitution might be a better way to handle things.

What it does, is basically run the command inside the parentheses. With the <() operator, the command's output is put in a named pipe (or something similar) that's created by bash. The operator itself in your command is replaced by the filename of that file. After your whole command finishes, the file is cleaned up.

Here's how we can put that into action: Imagine a situation where you want to see the difference between the output of two commands. Ordinarily, you'd have to put the two outputs in two files and diff those:

$ head -n 1 .dictionary > file1
$ tail -n 1 .dictionary > file2
$ diff -y file1 file2
Aachen                                                        | zymurgy
$ rm file1 file2

Using the Process Substitution operator, we can do all that with a one-liner and no need for manual cleanup:

$ diff -y <(head -n 1 .dictionary) <(tail -n 1 .dictionary)
Aachen                                                        | zymurgy

The <(..) part is replaced by the temporary FIFO created by bash, so diff actually sees something like this:

$ diff -y /dev/fd/63 /dev/fd/62

Here we see how bash runs diff when we use process substitution. It runs our head and tail commands, redirecting their respective outputs to the "files"/dev/fd/63 and /dev/fd/62. Then it runs the diff command, passing those filenames where originally we had put the process substitution operators.

The actual implementation of the temporary files differs from system to system. In fact, you can see what the above would actually look like to diff on your box by putting an echo in front of our command:

$ echo diff -y <(head -n 1 .dictionary) <(tail -n 1 .dictionary)
diff -y /dev/fd/63 /dev/fd/62

The >(..) operator is much like the <(..) operator, but instead of redirecting the command's output to a file, we redirect the file to the command's input. It's used for cases where you're running a command that writes to a file, but you want it to write to another command instead:

$ tar -cf >(ssh host tar xf -) .


Shell 输入/输出重定向

概述大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出...
  • yangshangwei
  • yangshangwei
  • 2016年08月31日 21:09
  • 3499

linux shell 脚本【3】 ---- 重定向 与 tee 命令

1.重定向: echo "ABCD"  > temp.txt 将ABCD写入到temp.txt中 echo "ABCD" >> temp.txt 讲ABCD追加到temp.txt中 其中 ...
  • liu_zhen_wei
  • liu_zhen_wei
  • 2014年01月08日 21:33
  • 7147

一个简单的例子来演示将stderr 同时 tee 到文件上

同事在使用 android的ndk_build 命令时,对输出作重定向,发现有很多打印没有被定向到文件。 其实, ndk_build xxx 2>&1 | tee ./build_log.txt...
  • code_think_write
  • code_think_write
  • 2012年04月27日 11:50
  • 914

第4章 处理用户输入与显示数据------------(标准文件描述符、STDIN/STDERR/STDOUT、临时重定向、永久重定向exec)

4.4 显示数据 4.4.1 标准文件描述符          Linux系统将每个对象当作文件处理。这包括输入和输出过程。Linux使用文件描述符(file descriptor)标识每个文件对象。...
  • henni_719
  • henni_719
  • 2016年12月12日 11:03
  • 653


echo输出到stderr On the unix command line, each command can print to stdout (standard output) or s...
  • cwj649956781
  • cwj649956781
  • 2014年08月01日 17:08
  • 2372


1,在linux中,标准输出和标准错误默认都是将信息输出到终端上,那么他们有什么区别呢?让我们来看个题目:问题:下面程序的输出是什么?(intel笔试2011)#include int main() ...
  • Q565220
  • Q565220
  • 2016年02月03日 17:03
  • 1701


玩linux的时候经常会看到stdin,stdout和stderr,这3个可以称为终端(Terminal)的标准输入(standard input),标准输出( standard out)和标准错误输...
  • qq_21792169
  • qq_21792169
  • 2016年01月06日 17:13
  • 17800


环境:Linux 一段执行时间很长的Python程序在linux后台执行,把结果输出到某文件:cmd='python '$1' '$2' '$3' '$5' '$4 RESULT=eval $cm...
  • wangshuang1631
  • wangshuang1631
  • 2016年12月27日 17:12
  • 1052


stdout, stdin, stderr的中文名字分别是标准输出,标准输入和标准错误。   在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据 流,也就是题目中所提到的...
  • yinjiabin
  • yinjiabin
  • 2012年04月01日 16:56
  • 15990

Linux stdin stdout stderr重新定向与管道

作者:Vamei 出处: 欢迎转载,也请保留这段声明。谢谢!...
  • mengyetxz
  • mengyetxz
  • 2016年10月11日 14:36
  • 1233
您举报文章:linux shell 屏幕显示stdout stderr的同时 分别重定向到文件