只问耕耘
分类: WINDOWS
2010-05-28 17:49:39
什么是二次重定向呢? >nul 2>nul 就是一个典型的二次重定向。一般情况下,二次重定向不会有问题产生,但也有例外,例如:
echo. 2>nul 3>nul
执行这个命令后,所有出错误提示均看不到了
echo. 1>nul 3>nul
执行这个命令后,所有的输出提示均看不到了(但是错误提示会显示)?
这两个命令却无法同时使用。
还有执行以下语句后将会一直循环显示,无法停上:
echo. 0>nul 3>nul
另外:
echo. 2>nul 3>test.txt
以后就会将出错信息写入到test.txt中.
同理,
echo. 1>nul 3>test.txt
就会将标准输出信息写入到test.txt中.
为什么会这样呢?
这确实是一个有意思且有意义的主题。关于这个奇怪的现象,因为未见于公开的官方文档,所以它似乎是介于未公开特性与程序算法漏洞之间的存在。
经过简单测试得到以下结论:
这个现象由句柄二次重定向所引起,与语句的命令主体无关;
二次重定向的目标可以不同,前次重定向影响本语句,后次重定向影响语句结束后的CMD环境;
后次重定向的句柄必须是未定义句柄,且必须在前次重定向之前未曾使用过;此次使用后即刻作废,不可重复用于缺省CMD环境的句柄重定向;
由此我对此现象的推测如下:
在CMD中的某一语句中实现句柄的修改(重定向或者复制)时,设计者为了实现在语句执行完后,恢复被修改的句柄,则必然会在修改之前复制(或者说备份)句柄,至于备份的目的地,CMD选择了从未曾使用过的“未定义句柄(3-9)”,这似乎是一个无可厚非的选择。但是程序在判断并获取未使用句柄时显然存在某些漏洞,它们首先处理第一个修改操作,在得到要修改的句柄后,立即寻找未使用的备份句柄,在找到备份句柄并进行备份后,才处理随后的修改操作,而此时这个备份句柄仍然可以被修改,导致在语句结束后,CMD会使用修改后的备份句柄恢复第一次修改的句柄,最后导致CMD的缺省句柄被修改。而此时CMD才得知备份句柄已被使用,而会在下一语句中修改句柄时使用其后的“未使用句柄”进行备份。
以下的语句应该也是类似的原理,只是更加准确的说明了获取备份句柄的时机。
pause 1>&3 3>nul
所以,CMD帮助文档中关于3-9是未定义句柄的说辞,应该是不够准确的,因为它确实会被系统移作他用,而并非“由应用程序单独定义,它们是各个工具特有的”,由此看来,它更像是“保留句柄”。
另外,CMD中句柄的行为显然更为复杂了,尤其是句柄复制的行为,即使微软的文档对此也是语焉不详。比如以下的语句可以将stdout复制到stderr,而stderr被重定向到了nul设备,结果导致pause的stdout重定向到nul设备,也即无输出。这是可理解的。
pause 2>nul 1>&2
而在下面的语句中,仅仅将复制与重定向的操作反转,便不再有效。而这也应与以上提到的CMD特性有关。
pause 1>&2 2>nul
最后需要提及的是,CMD中句柄具有读写属性,stdin是只读的,stdout是只写的,stderr是可读可写,其它未见定义。复制句柄的同时,也复制了句柄的读写属性。