欢迎光临

木子屋

标题: 重定向中的秘密

作者: dnawo

日期: 2009-01-09 00:38 AM

分类: 操作系统

内容: 本帖主要参考了《命令行参考》和一些前辈的文献，并加入了我自己的一些理解，希望能对各位有所帮助。
《命令行参考》中对重定向操作符有所论述，不过实在晦涩难懂，并且还有些错误，不利于大家理解。
重定向的简单用法相信大家都会，本帖的主要目的就是进一步研究一下重定向。
重定向符号主要有：>，>>，<，>&，<&和|，而本帖中只讨论前五个。
第一节
首先从一个经典问题开始，“1>nul 2>nul”的意思是既屏蔽正常的输出又屏蔽错误的输出，那么我们马上就知道了这里的1代表正常输出（即所谓的“标准输出”--stdout），2代表错误输出（即所谓的“标准错误输出”--stderr）。
1和2其实是句柄stdout和stderr的数字代号，至于什么是句柄，我认为可以理解为某种事物的一种标识，或者说这个句柄指向某个事物。举个例子来说，“标准输出”以句柄stdout为标识，或者说句柄stdout指向“标准输出”。
还有一个句柄--stdin，它是所谓“标准输入”的标识，数字代号是0。除此之外还有3~9可用，只是它们没有定义。
“标准输出”和“标准错误输出”默认是要输出到控制台con（即cmd窗口）的，而“标准输入”默认是由控制台con（即键盘）输入的，因此重定向的目的就是将输入输出流从默认位置重定向到新的位置。符号“>”和“>>”的默认句柄代号是1，而“<”的默认句柄代号是0。
“echo hhhhhh”类似于这样的语句可以说是我们再熟悉不过的了，但这只是种默认的状态，其实里面还有一些内容。这一句完整的应该是这样的：“echo hhhhhh 1>con 2>con”，意思是将echo命令的结果中的标准输出和标准错误输出输出到控制台con中，只不过此时标准错误输出是空的。
再看一个例子，如果给dir一个错误的参数，例如“dir /mm”，那么写全了就是“dir /mm 1>con 2>con”，只不过此时的标准输出是空的。如果你这样写的话“dir /mm 1>hero.txt”，那么屏幕上会照常显示错误信息但hero.txt中不会有内容。
再来一个标准输入的例子，“set /p var= ”其实应该是这样的“set /p var= 0<con”，只是因为0<con是默认值可以省略。我们当然可以从文件中读取输入，如“set /p var= 0<file.txt”，0是默认值可以省略。
nul代表的是“空设备”，是一个不存在的设备，将输出流重定向到空设备就相当于屏蔽掉了一样。而如果从空设备中读取输入，自然是读不到东西的，但的确是输入了，这也就是“set /p var=<nul”中“<nul”相当于回车但不换行的原因。
第二节
好了，说到这里，相信大家对重定向输出和输入又有了进一步的了解，关于重定向输出到文件和由文件重定向输入的问题在此也不再复述。我下面要讲的是句柄代码之间的“重定向”。
之前不是提到过还有3~9这7个句柄数字代号吗，这些究竟有什么用？说实话，基本没什么用，因此建议你如果不是迫切想知道这部分内容的话就不要往下看了。
“echo hero 1>hero.txt”这一句是将标准输出重定向到文件hero.txt，相当于将句柄代号1的指向由con变为hero.txt。“echo hero 3>hero.txt 1<&3”，这句的结果是生成了文件hero.txt，其内容为hero，过程是这样的：“3>hero.txt”是将句柄数字代号3的指向由“空”变为hero.txt；“1<&3”是将句柄数字代号3的指向复制给1的指向，此时1的指向就为hero.txt了，因此标准输出就被重定向到hero.txt中了。（说到这里，是不是觉得有点像指针呀。）
“i<&j”和“i>&j”的效果都是把j的指向复制给i。“echo hero >hero.txt 2>&1”这句的意思是，无论是标准输出还是标准错误输出都会被重定向到hero.txt中，具体过程：1的指向由con转为hero.txt，“2>&1”是把1的指向复制给2，此时2的指向也变为了hero.txt，因此1和2都会被重定向到hero.txt中。注意：1是符号“>”的默认句柄数字代号。
再看“echo hero 3>hero.txt”，这个为什么就不能将结果重定向到文件中呢？记住，我们要重定向的只有标准输入、标准输出和标准错误输出，因此真正“干活”的就只有0、1和2，因为它们分别指代了前面的三者，而3没有指代任何句柄只能作为间接量使用。
“more 3<hero.txt 0>&3”这句是显示文件hero.txt，具体过程：“3<hero.txt”把3的指向变为hero.txt，“0>&3”把3的指向复制给0，即0指向了hero.txt（只不过这次是从hero.txt中读取数据）。强调一下，真正能读取数据的是0而不是3，3只是作为中间量而已。刚才这句我们当然可以这么写：“more 0<hero.txt”或直接“more <hero.txt”。
再来一个例子“echo hero 5>hero.txt 4>&5 3<&4 1<&3”，结果输出到了hero.txt中。具体过程：5的指向变成hero.txt，“4>&5”把5的指向复制给4，“3>&4”把4的指向复制给3，“1>&3”把3的指向复制给1，最终1的指向就是hero.txt，则1所指代的标准输出就被重定向到了hero.txt。
第三节
注意：这一节的内容都是围绕着下面这个例子进行叙述的。
复制内容到剪贴板 程序代码@echo off
echo 英雄是好男人！！！
echo. 1>nul 3>nul
echo 英雄是白痴！！！
echo 英雄是傻逼！！！
echo 这是怎么回事，难道就不能骂骂英雄吗？？？ 1>con 4>con
pause
这究竟是怎么回事？为什么结果会如此出乎意料？
这里涉及到一个所谓“备份”的问题，就是在修改某个句柄代号的指向之前，系统会把该句柄代号原来的指向备份到截止到目前第一个指向为空的句柄代号中。目的是当这一行的程序结束之后，系统可以通过备份找回原来的指向。
在继续阅读之前建议你准备好纸笔，以便能记录下各个代号指向的变化，这样不至于混乱。
我们现在把焦点集中到这句“echo. 1>nul 3>nul”上来。这句究竟是如何工作的呢？
第一步：在运行“1>nul”之前，1的指向是默认值con，此时代号3~9的指向都是空（初始值），因此系统会把1的指向备份到3（因为3是第一个为空的代号），3就指向了con。就是说系统把1原来的指向复制给了3，目的是语句结束后能找回原来的指向，这就相当于备份。
第二步：现在3的指向是con。然而由于要运行“3>nul”，因此还要备份3的指向。此时4是空的，系统就把3的指向con复制给了4，即4现在指向con。就是说3以4为备份。
第三步：由于“3>nul”使得3指向了nul。
第四步：这行语句结束时，1要找回原来的指向，从以上叙述我们知道，3是1的备份，因此1要通过3来恢复“原来”的指向，但此时3的指向已经变为了nul，故1就指向nul。
第五步：而3要恢复原来的指向就要找4，4指向con，故3恢复为con；4原始指向是空的，其备份在5中，故4的指向恢复到空。
至此我们理顺一下，现在1指向nul，2指向默认值con，3指向con，4之后都是空指向。那么在运行后两句echo语句时由于1指向nul，即标准输出被重定向到空设备，故显示被屏蔽。
再来看看这句 “echo 这是怎么回事，难道就不能骂骂英雄吗？？？ 1>con 4>con” 这句是怎么工作的呢？
第一步：1当前指向是nul，由于要运行“1>con”，因此要进行备份。但此时3指向的是con非空，故系统将1的指向备份到4，即4指向nul。
第二步：又由于要运行“4>con”，故4现在的指向nul就又被备份到5中，5以后的事姑且省略。
第三步：运行完“4>con”之后4就指向con。
第四步：该行程序结束后，1要通过4来恢复指向。4指向con，故1指向con从而恢复了默认状态。而4找5，5指向nul，故4指向nul。
我们再数一数现在的情况，0指向con，1指向con，2指向con，3没动还是指向con，4指向nul，5以后都为空指向。
会不会有点乱？那就再好好的看几遍吧，我也实在没有什么好办法了。
第四节
我们已经知道“echo hero”相当于“echo hero 1>con 2>con”，con代表了控制台，可以把con看做是特殊的文件，这就是我们无法建立名为con文件的原因。
再对“>”和“>>”的重定向机制做个分析。当要重定向到的文件有隐藏或系统属性时，“>>”可以正常运行，而“>”就无法操作了。据此我推测，对于“>”的重定向输出，如果文件不存在当然是建立文件，而如果文件存在就先将文件删除，然后再新建文件，也就是说并非是覆盖文件的内容而是先删除文件再建立新文件。
通过第三节的讲解你应该明白为什么类似这样的语句“echo hero >nul >con >hero.txt >con”会以最后一个为准了吧。
最后需要注意一点的是--重定向输出无法输出到只读文件。

+ 查看当前日志评论 (0)

登录

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.578 ms

返回

标题: 重定向中的秘密

你没有权限发表评论

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.578 ms

返回

暂无评论

返回

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 0.594 ms

返回