日期:2014-05-16  浏览次数:20545 次

求解惑,Linux管道和重定向
最近看到一篇关于管道的文章中有这样的描述:

alias testcmd='command ls -ld / xxx ~/.bashrc yyy' 
# swap stdout & stderr stream, i.e.  
# let the stderr stream pass through a pipe while the stdout is printed to the terminal only  
# cf. http://tldp.org/LDP/abs/html/io-redirection.html:  
# "Child processes inherit open file descriptors. This is why pipes work. 
# To prevent an fd from being inherited, close it."  
(
exec 3>&1  
testcmd 2>&1 1>&3 3>&- | tr '[[:lower:]]' '[[:upper:]]' 3>&-   
exec 3>&-  
)

在我的RHEL上输出是这样的:
drwxr-xr-x 26 root  root 4096 Oct  7 22:37 /
-rw-r--r--  1 admin root  497 Aug 14 14:31 /home/admin/.bashrc
LS: XXX: NO SUCH FILE OR DIRECTORY
LS: YYY: NO SUCH FILE OR DIRECTORY

1>&3 3>&-这句,关闭3并不会导致1被block,由此可见,1>&3并不是一个套接的效果,而是一个赋值。也就是说,1->stdout, 运行1>&3之后,得到的是3->stdout,而不是1->3->stdout。那么问题是,2>&1 1>&3将导致1和2都指向stdout,bash如何鉴别谁需要进入管道?
我有一种猜想,就是因为有管道符的存在,所以testcmd 2>&1中的&1其实已经不再指stdout,而是作为tr命令的输入管道。大家觉得对么?元方,你怎么看?
------解决方案--------------------
重定向其实是个文件描述符dup的过程,以你的例子而言:

testcmd 1>>log 2>&1 
这个命令是先把log的文件描述符dup给fd1,此时fd1的文件表项指向的就是log文件,再把fd1 dup给fd2,这样fd2也指向了log文件

testcmd 2>&1 1>>log
这个命令先把fd1 dup给了fd2, 这样fd1和fd2的文件表项指向的都是终端设备,再把log的文件描术符dup给fd1,这样fd2仍然指向终端设备,fd1指向了log文件



引用:
感谢答复。我似乎明白了一些。但还是觉得有问题。
你在回复中也说"原来fd 1的内容被重定向到了fd 3",可见1出现在>的左右,是有不同的含义的。那么这个含义是什么呢?我试着将>左边的1理解成这个command的stdout,1理解成这个command的stderr,而>右边的1,2,3则表示这个process的fd。但这样的理解似乎也不对,因为众所周知改变重定向出现的……