note:這是對cmd
執行 重定向命令時發生的簡化。
讓我們先從指定的命令
0< file1 3< file2 echo/
命令進行分析,而需要重定向的表示在內存中創建,某些類型的表/列表,將舉行關於重定向的信息:該手柄重定向,老保存的手柄,到時重定向,手柄應該指向...
Redirection requests
-------------------------------
redirect saved redirectTo
+--------+--------+------------
R1 | 0 file1
|
R2 | 3 file2
此時(解析命令後)沒有流已經改變。
還有一個系統表,用於處理每個文件描述符(在我們的例子中爲cmd
流)真正指向的位置。
File descriptors
------------------
points to
+-----------------
0 | stdin
1 | stdout
2 | stderr
3 |
4 |
注這是不完全正確,基本結構是一個稍微複雜一些,但這樣很容易看到它是如何工作
當命令將被執行,內部調用SetRedir
函數。它迭代前一個重定向請求表,保存現有的句柄並創建所需的新句柄。初始狀態是
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)創建一個別名。保存操作老手柄收盤後的情況是
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()
函數處理操作
_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)
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 <<--/
重定向由與文件描述符
_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重定向到file1
並且流3重定向到file2
的情況下執行。
完成後,是時候恢復過程。 ResetRedir()
函數處理操作。它再次使用_dup2()
函數將保存的句柄傳輸到原始文件描述符。在這裏,出現問題的保存描述改爲
_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
現在,一旦重定向已被刪除&0
把手指向file2
和stdin
相同的操作與第二重定向
_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 | ---/
完成流存儲在&3
中。這可以作爲
@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
讀取,而在第二次測試,試圖從&3
閱讀可以到達stdin
流。
哇,優秀的答案,+1!這導致我另一個失敗的場景:'3 stream1.txt 3> stream3.txt echo /'('cmd'掛起,直到輸入'exit'),或者2> stream2.txt 3> stream3.txt echo /'(重定向的句柄'2'似乎沒有正確關閉);它看起來像內部過程是相同的輸入和輸出重定向... –
aschipfl
所以我認爲我可以說,作爲一項規則:*»預定義的手柄'0' /'1' /'2'重定向後,不要爲同一個命令行/塊使用下一個空閒句柄(既不用於輸入也不用於輸出重定向)。«* – aschipfl
@aschipfl,輸入和輸出重定向在同一個函數中處理,在同一個循環中,它只佔手柄更換。主要區別僅在於新手柄的檢索方式。在你的'1> stream1.txt 3> stream3中。txt echo /'case,'cmd'不會被絞死,只是'stdout'被髮送到'stream3.txt'。一般規則是定義從較高到較低流的重定向(如果可能)。 –