note: Dies ist eine Vereinfachung das, was in cmd
geschieht, wenn die Befehl ausgeführt wird umgeleitet.
Beginnen wir mit dem angegebenen Befehl starten
0< file1 3< file2 echo/
Der Befehl analysiert wird und eine Darstellung der benötigten Umleitungen im Speicher, eine Art von Tabelle/Liste erstellt, die die Informationen über die Umleitung halten: die hand umgeleitet wird, den alten gespeicherte Griff, wo der Griff zeigen soll, wenn, umgeleitet ...
Redirection requests
-------------------------------
redirect saved redirectTo
+--------+--------+------------
R1 | 0 file1
|
R2 | 3 file2
an dieser Stelle (nach dem Befehl Parsen) hat keinen Strom geändert.
Es gibt auch eine Systemtabelle, die behandelt, wo jeder der Dateideskriptoren (in unserem Fall die cmd
Streams) wirklich zeigt.
File descriptors
------------------
points to
+-----------------
0 | stdin
1 | stdout
2 | stderr
3 |
4 |
note Dies ist nicht ganz richtig, die zugrundeliegende Struktur ein wenig komplexer ist, aber auf diese Weise es leichter zu sehen ist, wie es
arbeitet Wenn der Befehl ausgeführt werden soll wird die interne SetRedir
Funktion aufgerufen. Es wird über die vorherige Umleitungsanforderungstabelle iteriert, wobei vorhandene Handles gespeichert und erforderliche neue erstellt werden. Der Anfangszustand ist
Redirection requests File descriptors
------------------------------- ------------------
redirect saved redirectTo points to
+--------+--------+------------ +-----------------
R1 | 0 file1 0 | stdin
| 1 | stdout
R2 | 3 file2 2 | stderr
3 |
4 |
erstes Element aus Umleitungsanforderungstabelle (R1) abgerufen wird, um die Anforderungen Strom 0 bis file1 zu umleiten. Es ist notwendig, das aktuelle Handle zu speichern, um es später wiederherstellen zu können. Für diese Operation wird die _dup()
-Funktion verwendet. Es wird ein Alias für den übergebenen Dateideskriptor (Stream 0 in unserem Code) erstellt, wobei der kleinste verfügbare Dateideskriptor verwendet wird (Datenstrom 3 in der vorherigen Tabelle). Nach der Operation und alten Griff nahe speichert die Situation
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 |
Einmal gespeichert ist, wird die Umleitung durch das Öffnen der angeforderte Datei und Griffes in der Datei-Deskriptoren Tabelle Zuordnung offene Datei abgeschlossen.In diesem Fall übernimmt die _dup2()
Funktion den Betrieb
_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 |
Die erste Umleitung erfolgt ist. Es ist Zeit, die gleiche Operation mit die zweite zu tun. Speichern Sie zuerst das alte Handle mit der Funktion _dup()
. Dies wird den angeforderte Datei-Deskriptor (3) mit dem niedrigsten verfügbaren Deskriptors assoziieren (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 <<--/
Die Umlenkung durch Öffnen der Eingabedatei abgeschlossen ist, und es mit dem Dateideskriptor Assoziieren
_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
Die Umleitung wurde abgeschlossen und der Befehl wird ausgeführt, wobei der Stream 0 an file1
umgeleitet und der Stream 3 an file2
umgeleitet wurde.
Sobald dies erledigt ist, ist es Zeit, den Prozess rückgängig zu machen. ResetRedir()
Funktion verarbeitet die Operation. Es verwendet erneut die Funktion _dup2()
, um das gespeicherte Handle in den ursprünglichen Dateideskriptor zu übertragen. Hier stellt sich das Problem, wie die gespeicherte Descriptor
_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
nun geändert wurde, wird der gleiche Vorgang mit dem zweiten Umleitung erfolgt
_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 | ---/
Sobald die Umleitung der &0
Griffpunkte auf file2
und der stdin
entfernt wurde Strom wird in &3
gespeichert. Dies kann als
@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 !.!"
getestet werden, dass
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:\>
generiert Es ist ersichtlich, dass in dem ersten Test die set /p
von file2
gelesen hat, und in dem zweiten Test, versucht, von &3
zu lesen Der stdin
Stream kann erreicht werden.
Wow, ausgezeichnete Antwort, +1 !! Dies führte mich zu einem anderen Szenario, das fehlschlägt: '3 stream1.txt 3> stream3.txt echo /' ('cmd' hängt, bis ich' exit' eingebe), oder '2> stream2.txt 3> stream3.txt echo/'(umgeleiteter Handle' 2' scheint nicht richtig geschlossen zu sein); es sieht so aus, als wäre der interne Prozess für die Ein- und Ausgangsumleitung der gleiche ... –
aschipfl
Also ich denke, ich könnte in der Regel sagen: * »Nach Umleitung eines vordefinierten Handle' 0'/'1' /' 2', Verwenden Sie nicht das nächste freie Handle (weder für die Eingabe noch für die Ausgabeumleitung) für die gleiche Befehlszeile/den gleichen Block. «* – aschipfl
@Aschipfl, Eingabe- und Ausgabeumleitung werden innerhalb der gleichen Funktion behandelt, innerhalb derselben Schleife Griff Ersatz. Der Hauptunterschied besteht nur darin, wie das neue Handle abgerufen wird. In Ihrem '1> stream1.txt 3> stream3.txt echo/'case,' cmd' wird nicht gehängt, es wird nur 'stdout' an' stream3.txt' gesendet. Die allgemeine Regel besteht darin, Umleitungen (wenn möglich) von höheren zu niedrigeren Strömen zu definieren. –