Linux I/O Redirection Updated June 01, 2005 Created October 11, 2001
术语:stdout(标准输出),stdin(标准输入),stderr(标准错误)。
(此文档主要解释输入输出重定向(< >),管道(|)和tee命令的使用。)
命令示例
以下命令将stdout和和stderr分别保存到文件”out.txt”和”err.txt”中。
[kyle@server]$ ./cmd 1>out.txt 2>err.txt
以下命令将stdout和和stderr分别添加到文件”out.txt”和”err.txt”中。
[kyle@server]$ ./cmd 1>>out.txt 2>>err.txt
以下命令跟前两个命令相似,但会分别复制一份stdout和和stderr到文件”stdout.txt”和”stderr.txt”。
[kyle@server]$ (((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > |tee stderr.txt) 3>&1 1>&2 2>&3) 1>out.txt 2>err.txt
Note:反斜杠()表示下行继续。当一行太长影响排版时,可以这样处理。
* Tar命令示例
[kyle@server]$ (cd /var/ftp/pub/rh71prof/disk1.iso.dir > && tar -cvf - .) | (cd /var/ftp/pub/rh71prof/i386 && tar -xvf -)
* Find命令示例-在每个文件里搜索指定字符串
[kyle@server]$ find . -type f -exec grep -i > searchstring {} --with-filename ;
注:-i表示-ignore-case,不分大小写。–with-filename可以用-H代替。{}前的两个反斜杠非必须。
* 测试脚本示例
#!/bin/sh # 你可以用这个示例脚本测试。echo语句解释脚本是怎样工作的。 echo "This is Standard Out" >&1 echo "This is Standard Error" >&2
* for循环的stdout和stderr示例
#/bin/sh echo Standard Out >stdout.txt echo Standard Error >stderr.txt for X in bzImage modules modules_install; do make $X; done 1>>stdout.txt 2>>stderr.txt
* Linux的重定向
0 = 标准输入(stdin)
1 = 标准输出(stdout)
2 = 标准错误(stderr)
* 用tee命令将stdout保存到tee.txt文件,stdout同时显示到屏幕上。
[kyle@server]$ cmd | tee tee.txt
* 用tee命令将stdout添加到tee.txt文件,stdout同时显示到屏幕上。
[kyle@server]$ cmd | tee -a tee.txt
* 用script命令同时捕获stderr和stdout。
[kyle@server stdout]$ script Script started, file is typescript [kyle@server stdout]$ ./cmd This is Standard Out This is Standard Error [kyle@server stdout]$ exit exit Script done, file is typescript [kyle@server stdout]$ cat typescript Script started on Thu Oct 11 11:47:36 2001 [kyle@server stdout]$ ./cmd This is Standard Out This is Standard Error [kyle@server stdout]$ exit exit Script done on Thu Oct 11 11:47:39 2001 [kyle@server stdout]$
* 关于管道(pipe,|)
- 把它想像成一个stdout或stderr的通道。
- pipe只能有一个通道,也就是stdout。
- 当你在命令中用到pipe时,stderr显示到屏幕上,而stdout发送到pipe,等待其他命令把它用做输入。
- 交换stdout和stderr后,会让stdout显示到屏幕,而stderr发送到pipe里。
- pipe自己只会接收stdout。如果你在使用pipe前,交换了stdout和stderr,那么pipe就会接收交换后的stdout(也就是stderr)。
- stdout和stderr可以合并起来发送到pipe里。但是,这样会让你无法区分stdout和stderr。
- 在子shell(subshell)”()”中使用pipe,会让stdout发送到pipe里,而stderr显示屏幕上。一般来说,你可以从子shell中把stdout和stderr都获取出来。
* 重定向的顺序
o 方法一
[kyle@server]$ cmd 2>&1 1>outfile.txt
#以上命令让stderr重定向到stdout,而原来的stdout则重定向到outfile.txt。
#注意,在fd(file descriptor,文件描述符)2被重定义时,fd 1仍然指向stdout。fd 2会继续指向stdout,不管fd1后来改变了什么。基本上,fd 2只是复制了fd 1指向的地址。
o 方法二
#以下命令把stdout和stderr都重定向至outfile.txt。
[kyle@server]$ cmd 1>outfile.txt 2>&1
#注意,stdout(1)重定向到outfile.txt,而2被重定义到1,两个通道合并了。
用Tee捕捉stderr,交换stderr和stdout
命令
[kyle@server]$ (((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 | tee stderr.txt) 3>&1 1>&2 2>&3) 1>out.txt 2>err.txt
解释
以下部分将详细解释这个长命令。当你了解了它的原理后,你将能很容易地把它重新写出来。
1. ./cmd 脚本的内容
#!/bin/sh # 你可以用这个示例脚本测试。echo语句解释脚本是怎样工作的。 echo "This is Standard Out" >&1 echo "This is Standard Error" >&2
2. ./cmd 脚本运行的结果
[kyle@server]$ ./cmd This is Standard Out This is Standard Error [kyle@server]$
虽然两行都显示在屏幕上,但其实它们一行是stdout,另一行是stderr。假如使用管道的话,只有stdout会输出到管道里来。
3. 捕获 stdout
以下命令会复制一份stdout到文件stdout.txt。
[kyle@server]$ ./cmd | tee stdout.txt
stdout输出到管道里,tee将其复制一份保存到stdou.txt文件里。但,这里我们失去了对stderr的控制。stderr不会输出到管道,而是直接输出到屏幕上。
4. 同时控制stderr和stdout
通过用括号把命令括起来,我们取得了对stderr的控制。
[kyle@server]$ (./cmd | tee stdout.txt)
5. 交换stdout和stderr。
我们已经可以保存stdout了,现在我们想用tee把stderr也保存起来。管道只接受stdout的输入,所以我们必须交换stderr和stdout来达到我们的目的。
注意:交换使用了标准的变量交换方式——需要用到3个变量来使2个变量完成互换。(你有两个变量,你要交换它们的内容,必须用到一个临时变量来辅助。)
[kyle@server]$ (./cmd | tee stdout.txt) 3>&1 1>&2 2>&3
6. 捕获stderr
现在我们交换了stdout和stderr,来加上tee命令。tee现在可以捕获stderr了(tee相信那就是stdout,因为stdout是唯一能输出到管道里的东西)。
[kyle@server]$ (./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > | tee stderr.txt
7. 再次同时控制stderr和stdout
tee捕获了stderr,但stdout又直接输出到屏幕上去了。让我们再次用括号来同时控制stderr和stdout。
[kyle@server]$ ((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > | tee stderr.txt)
8. 把stdou和stderr换回去
现在我们再次把stderr和stdout都捕获了。目前它们是互换过了的。让我们把它们换回去。再次使用标准交换方法。
[kyle@server]$ ((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > | tee stderr.txt) 3>&1 1>&2 2>&3
9. 第三次同时控制stderr和stdout
现在我们已经把stdout和stderr换回去了。但如果我们还想对stdout和stderr做进一步的操作,必须加上一个管道或另一对括号。
这里我们使用括号。用括号可以同时控制stdout和stderr。而用管道只能控制stdout。
注意:如果我们用一个管道或加一对括号,接下来的命令能恰当地区分stderr和stdout。如果不加括号,不要管道,stderr和stdout的顺序就仍是混乱的。
[kyle@server]$ (((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > | tee stderr.txt) 3>&1 1>&2 2>&3)
10. 把stdout和stderr重定向到不同的文件里
现在我们来做些什么,以证明stdout和stderr真的被换回到原来的位置上了。我们让命令把stdout重定向到out文件,stderr重定向到err文件。
[kyle@server]$ (((./cmd | tee stdout.txt) 3>&1 1>&2 2>&3 > | tee stderr.txt) 3>&1 1>&2 2>&3) 1>out.txt 2>err.txt
注意out和err文件的内容跟运行以下命令的内容相同。这证明我们把stdout和stderr换回到它们原来的位置上了。以上命令让我们可以用tee复制一份stdout和stderr保存到文件里,同时它们还像往常发挥功能。
[kyle@server]$ ./cmd 1>out.txt 2>err.txt
在一个文件里保存stderr,另一个文件里保存stderr和stdout
我想把stderr保存到一个文件里,stderr和stdout合并保存到另一个文件里,可以这样:
这是我们的让stderr和stdout定向到合适的通道里的测试命令:
kyle@server:~> (echo out >&1; echo err >&2) out err
这是能工作的命令:
kyle@server:~> (((echo out >&1; echo err >&2) 3>&2 2>&1 1>&3 | tee stderr.txt ) 3>&2 2>&1 1>&3 ) > combined.txt 2>&1 kyle@server:~> cat stderr.txt err kyle@server:~> cat combined.txt out err
其他资料
http://www.cpqlinux.com/jobcontrol.html
bash 手册:man bash
/myprog.sh 的内容
#!/bin/bash echo "Standard Out" >&1 echo "Standard Error" >&2
把stdout保存到stdout.log,stderr保存到stderr.log,然后把它们都显示到屏幕上:
((( ./myprog.sh | tee stdout.log ) 3>&2 2>&1 1>&3 | tee stderr.log ) 3>&2 2>&1 1>&3 )
最后把stdout和stderr换回来,只是为了方便对它们的进一步操作。
把stdout保存到stdou.log,stderr保存到stderr.log,然后把stdout和stderr合并保存到combined.log,最后把它们显示到屏幕上:
((( ./myprog.sh | tee stdout.log ) 3>&2 2>&1 1>&3 | tee stderr.log ) 3>&2 2>&1 1>&3 ) 2>&1 | tee combined.log