首页 > 学技术 > 技术网文 > Linux Shell > 正文

[原创] 剖析cmd >file 2>&1 和 cmd >file 2>file 的差别


来源 chinaunix.net 酷勤网整理

先看例子:

r2007@www r2007 $ (echo -n 123456;sleep 1;echo -n abc >&2;sleep 1;echo -n 789)>puzzle 2>puzzle
r2007@www r2007 $ cat puzzle
abc456789
r2007@www r2007 $ (echo -n 123456;sleep 1;echo -n abc >&2;sleep 1;echo -n 789)>puzzle 2>&1
r2007@www r2007 $ cat puzzle
123456abc789

为了强调每个输出都是step by step,所以加了sleep命令,其实可以省略。(echo ....)等同于一个cmd命令,在这里用一组echo命令是为了能清晰的看到整个操作过程。
第一种用法实际上同时打开2次puzzle文件。过程如下:
>puzzle ---- 打开puzzle文件(打开文件的操作会在核心中产生一个数据结构-假设叫做foo结构,其中有很多参数,比如file position-以下简称fp,就是其中之一),然后fd1(标准输出)保存着这个指针(具体结构没做深入分析,姑且简化为保存了一个指针),总而言之,通过fd1可以引用到这个核心中的数据结构。
2>puzzle --- 基本同上,再次打开这个文件,核心中会产生一个新的数据结构,同时fd2(标准错误输出)保存了这个结构的指针。
一开始,这两个foo结构中的fp都是0,第一个echo在puzzle文件写入了123456,同时fd1所指向的foo结构中的fp变为6,然后第二个echo要在puzzle文件写入abc,但是它得到的fp是fd2所指向的foo结构中的fp,所以仍然从文件头开始写,所以puzzle中的内容变为abc456,第三个echo就不再罗嗦一遍了,它是从6这个位置开始写操作的。

为什么cmd >file 2>&1这种模式就不会发生混乱呢?
就是因为2>&1,不是再打开一次文件,而是fd2照抄fd1,这两个fd共用一个foo结构,所以它们使用的fp也是同一个。

以下例子可以加深理解这个道理:
(echo -n 123;sleep 1;echo -n abcde >&2;sleep 1;echo -n 789) >puzzle 2>puzzle

结果:abc789


 (echo -n 123;sleep 1;echo -n abcdeghij >&2;sleep 1;echo -n 789) >puzzle 2>puzzle

结果:abc789hij


对于编程我是个外行,其中如有错误的概念,欢迎指正。



 大蚂蚁 回复于:2006-05-31 01:07:41

讲的很好哈,我倒是第一个看倒这个帖子了,两个echo用的很好!看完后一目了然!全理解了。


不过,有个小小的问题,对于2>&1这种情况,会不会出现信息量特别大,存放错误信息的(fd2)错误缓冲区满了怎么办?会出现什么情况?
或者是这种情况不会发生?当然我说的有点极端。只是对这个处理方法的一点点疑问。


 寂寞烈火 回复于:2006-05-31 02:19:36

真有趣~~~
引用:
/home/lee#ls a b >c 2>c
/home/lee#cat c
a
: b: 没有那个文件或目录
/home/lee#ls a b >c 2>&1
/home/lee#cat c
ls: b: 没有那个文件或目录
a
/home/lee#




 r2007 回复于:2006-05-31 10:41:49

引用:原帖由 大蚂蚁 于 2006-5-31 01:07 发表
讲的很好哈,我倒是第一个看倒这个帖子了,两个echo用的很好!看完后一目了然!全理解了。


不过,有个小小的问题,对于2>&1这种情况,会不会出现信息量特别大,存放错误信息的(fd2)错误缓冲区满了怎 ... 


没理解透你说的这种情形,2>&1的方式是公认的标准做法,应该不会有问题。


 網中人 回复于:2006-05-31 11:51:15

太好了!
r2007 兄的分析也幫我修正了之前的錯誤觀念. 感謝!!  ^_^


 yjh777 回复于:2006-05-31 11:59:22

引用:原帖由 大蚂蚁 于 2006-5-31 01:07 发表
讲的很好哈,我倒是第一个看倒这个帖子了,两个echo用的很好!看完后一目了然!全理解了。


不过,有个小小的问题,对于2>&1这种情况,会不会出现信息量特别大,存放错误信息的(fd2)错误缓冲区满了怎 ... 


我以前测试过() 里的信息的内存使用量,在bash 中没有设上限。
结果用top 察看内存使用量接近500M 的时候,由于系统负载过大
那个subshell 进程被内核kill 掉了。


默认跟文件描述符2(fd2)关联的是终端设备(这里应该是属于字符设备)文件。缓冲区是终端程序的缓
冲,它一般设定为一个固定值,只保留最近的n行信息,并及时把这些信息写入终端设备文件。

如果重定向这些信息到磁盘文件的话,那就是通过磁盘文件系统(ext2/fat32/ufs)先把这些数据写到磁盘
缓冲区,然后在适当的时候再通过块设备驱动程序把磁盘缓冲区中的脏页写到磁盘上。

linux下很多东西都当文件处理,由文件系统层统一处理,有时间看看虚拟文件系统和读写系统调用的处理过
程对理解很有帮助。
其实我也是一知半解,请大家指正。


 r2007 回复于:2006-05-31 12:01:47

网兄客气了。
只有互相交流才是学习的最好方法。
希望这个实验的推论能经得起推敲。


 大蚂蚁 回复于:2006-05-31 16:20:27

我的问题可能是多余的,不过r2007也是一个好老师了,以前这个问题没相通,这次两个echo就通了,赞一个。
yjh777 说的也有一定道理,似乎比较合逻辑,呵呵




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=764727
转载请注明作者名及原文出处



收藏本页到: