为什么不能按此顺序重定向到两个输入流“ 0lt;”和“ 3<”? [英] Why can't I redirect to two input streams `0<` and `3<` in that order?

查看:58
本文介绍了为什么不能按此顺序重定向到两个输入流“ 0lt;”和“ 3<”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试将多个文件重定向到多个流中时,如以下示例所示,一切都会按预期进行:

When I try to redirect multiple files into multiple streams, like in the following example, everything works as expected:

3< stream3.txt 4< stream4.txt echo/

类似的东西还可以用于比<$>更多的流和文件以及其他命令c $ c> echo / 甚至是功能代码块。即使使用保留的输出流 1 2 似乎也可以正常工作。

Something like that works also with more streams and files and other commands than echo/ or even a functional block of code. Even using the reserved output streams 1 and 2 seem to work properly.

但是,只要我按照给定的顺序使用以下流,就可以这样做:

However, as soon as I do that with the following streams in the given order:

0< stream0.txt 3< stream3.txt echo/

托管命令提示符实例立即关闭。

The hosting command prompt instance is immediately closed.

当我更改流的顺序时,它又能正常工作:

When I change the order of the streams, it works fine again:

3< stream3.txt 0< stream0.txt echo/

为什么 cmd 0 3 的顺序时c>实例意外终止了吗?

So why is the cmd instance terminated unexpectedly when I try to input-redirect to stream 0 and 3 in that order?

我正在使用Windows 7(x64)。

I am using Windows 7 (x64).

打开时在尝试执行上述失败的输入重定向之前,由 cmd 创建一个新的命令提示符实例:

When I open a new command prompt instance by cmd before I try to executed the aforementioned failing input redirection:

cmd
0< stream0.txt 3< stream3.txt echo/

我可以阅读出现的错误消息-假设文本文件包含它们的基本内容名称后跟一个换行符:

I can read the appearing error message -- supposing the text files contain their base name followed by a line-break:


'stream3' is not recognised as an internal or external command, operable program or batch file.


当我执行以下操作时,我可以看到两个文件都是实际重定向:

When I do the following, I can see that both files are actually redirected:

cmd /V
0< stream0.txt 3< stream3.txt (set /P #="" & echo/!#!)

cmd /V
0< stream0.txt 3< stream3.txt (<&3 set /P #="" & echo/!#!)

各自的输出:

stream0

并且:

stream3

这到底是怎么回事?

推荐答案

注释:这是执行
重定向命令时 cmd 内部发生的事情的简化。

note: This is a simplification of what happens inside cmd when the redirected command is executed.

让我们从指示的命令开始

Let's start with the indicated command

0< file1  3< file2 echo/

解析命令并在内存中创建所需重定向的表示形式表/列表中将保存有关重定向的信息:哪个句柄被重定向,旧的保存的句柄,在重定向时该句柄应指向的位置,...

The command is parsed and a representation of the needed redirections is created in memory, some kind of table/list that will hold the information about the redirection: which handle is redirected, the old saved handle, to where the handle should point when redirected, ...

    Redirection requests
   ------------------------------- 
    redirect   saved   redirectTo
   +--------+--------+------------
R1 | 0                 file1
   |
R2 | 3                 file2

在这一点上(解析命令后),流没有被更改。

At this point (after parsing the command) no stream has been changed.

还有一个系统表,用于处理每个文件描述符(在我们的示例中为 cmd 流)真正指向的位置。

There is also a system table that handles where each of the file descriptors (in our case, the cmd streams) really points.

    File descriptors
   ------------------  
    points to
   +----------------- 
 0 | stdin
 1 | stdout
 2 | stderr
 3 |
 4 |

note 这并非完全正确,其基本结构是稍微复杂一点,但是那样一来,它的工作原理就更容易了。

note This is not exactly true, the underlying structure is a little more complex, but that way it is easier to see how it works

要执行命令时,内部 SetRedir 函数被调用。它遍历先前的重定向请求表,以保存现有的句柄并创建所需的新句柄。初始状态为

When the command is going to be executed, the internal SetRedir function is called. It iterates over the previous redirection request table saving existing handles and creating required new ones. The initial state is

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0                 file1                  0 | stdin
   |                                          1 | stdout
R2 | 3                 file2                  2 | stderr
                                              3 |
                                              4 |

检索到重定向请求表(R1)中的第一个元素,该请求将流0重定向到file1。必须保存当前的句柄,以便以后能够还原它。对于此操作, _dup() 函数。它将使用最小的可用文件描述符(上表中的流3)为传递的文件描述符(代码中的流0)创建别名。保存操作和旧句柄关闭后,情况是

First element from redirection request table (R1) is retrieved, the requests to redirect stream 0 to file1. It is necessary to save the current handle to later be able to restore it. For this operation the _dup() function is used. It will create an alias for the passed file descriptor (stream 0 in our code), using the smallest available file descriptor (stream 3 in previous table). After save operation and old handle close the situation is

   R1[saved] = _dup( R1[redirect] );
   _close( R1[redirect] );

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0        3        file1                  0 |          ---\
   |                                          1 | stdout      | 
R2 | 3                 file2                  2 | stderr      |
                                              3 | stdin   <<--/
                                              4 |

保存后,通过打开请求的文件和
关联打开文件句柄来完成重定向在文件描述符表中。在这种情况下,
_dup2() 函数处理该操作

Once saved, the redirection is completed by opening the requested file and associating open file handle in the file descriptors table. In this case the _dup2() function handles the operation

 _dup2( CreateFile( R1[redirectTo] ), R1[redirect] );

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0        3        file1                  0 | file1   <<---
   |                                          1 | stdout
R2 | 3                 file2                  2 | stderr
                                              3 | stdin 
                                              4 |

第一次重定向已完成。现在是时候对第二个
执行相同的操作了。首先,使用 _dup()函数保存旧句柄。这会将请求的文件描述符(3)与最低可用描述符(4)关联起来。

The first redirection has been done. It is time to do the same operation with the second one. First, save the old handle using the _dup() function. This will associate the requested file descriptor (3) with the lowest available descriptor (4)

   R2[saved] = _dup( R2[redirect] );
   _close( R2[redirect] );

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0        3        file1                  0 | file1
   |                                          1 | stdout
R2 | 3        4        file2                  2 | stderr
                                              3 |         ---\
                                              4 | stdin  <<--/

重定向是通过打开输入文件并将其与文件描述符

The redirection is completed by opening the input file and associating it with the file descriptor

_dup2( CreateFile( R2[redirectTo] ), R2[redirect] );

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0        3        file1                  0 | file1
   |                                          1 | stdout
R2 | 3        4        file2                  2 | stderr
                                              3 | file2  <<---
                                              4 | stdin

重定向已完成,并且在将流0重定向到<$ c $的情况下执行了命令c> file1 ,流3重定向到 file2

The redirection has been completed and the command is executed with the stream 0 redirected to file1 and the stream 3 redirected to file2.

完成后,时间恢复该过程。 ResetRedir()函数处理该操作。它再次使用 _dup2()函数将保存的句柄传输到原始文件描述符。此处的问题是由于更改了保存的描述符

Once done, it's time to revert the process. ResetRedir() function handles the operation. It uses again the _dup2() function to transfer the saved handle to the original file descriptor. Here the problem arises as the saved descriptor was changed

_dup2( R1[saved], R1[redirect] );
R1[saved] = null;

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0                 file1                  0 | file2  <<--\
   |                                          1 | stdout     |
R2 | 3        4        file2                  2 | stderr     |
                                              3 |         ---/
                                              4 | stdin

现在,第二个重定向操作执行相同的操作

Now, the same operation is done with the second redirection

_dup2( R2[saved], R2[redirect] );
R2[saved] = null;

    Redirection requests                         File descriptors
   -------------------------------              ------------------
    redirect   saved   redirectTo                points to
   +--------+--------+------------              +-----------------
R1 | 0                 file1                  0 | file2
   |                                          1 | stdout
R2 | 3                 file2                  2 | stderr
                                              3 | stdin  <<--\
                                              4 |         ---/

删除重定向后,& 0 句柄指向 file2 ,而 stdin 流存储在& ; 3 。可以测试为

Once the redirection has been removed the &0 handle points to file2 and the stdin stream is stored in &3. This can be tested as

@echo off
    setlocal enableextensions disabledelayedexpansion

    >file1 echo This is file 1
    >file2 echo This is file 2

    echo Test 1 - trying to read from stdin after redirection
    cmd /v /c"( 0< file1 3< file2 echo - test1 ) &     set /p .=prompt & echo !.!"

    echo(
    echo(

    echo Test 2 - trying to read from stream 3 after redirection
    cmd /v /c"( 0< file1 3< file2 echo - test 2 ) & <&3 set /p .=prompt & echo !.!"

将生成

W:\>testRedirection.cmd
Test 1 - trying to read from stdin after redirection
- test1
prompt This is file 2


Test 2 - trying to read from stream 3 after redirection
- test 2
prompt This is typed text
This is typed text

W:\>

可以看出,在第一个测试中, set / p 已从 file2 <读取。 / code>,然后在第二个测试中,尝试从& 3 中读取 stdin 流达到。

It can be seen that in the first test, the set /p has read from file2, and in the second test, trying to read from &3 the stdin stream can be reached.

这篇关于为什么不能按此顺序重定向到两个输入流“ 0lt;”和“ 3&lt;”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆