25

In Windows, either in command line or a batch file, the command DIR 2>NUL: 3>&2 (you can replace DIR with anything, even if isn't a file or a command) will make all errors from then on missing unless you write 2>CON: after every command. Why is CMD even doing this? And how do you get it back to normal without starting a new CMD process? DIR 2>CON: 3>&2 will only work for that command alone.

EDIT: This will work with files as well. DIR 2>TEXT.TXT 3>&2 Any errors after that will be appended to the file.

daaawx
  • 3,273
  • 2
  • 17
  • 16
Erbert
  • 321
  • 1
  • 3
  • 8

4 Answers4

37

Here is a test script that reproduces the problem you are seeing.

@echo off
2>nul 3>nul (
  echo I want to see stream1
  1>&2 echo I don't want to see this stream2
  1>&3 echo I don't want to see this stream3
)
echo stream1 works fine
1>&2 echo stream2 is now "permanently" void. I don't see this.
1>&3 echo stream3 works fine

And here is the output

I want to see stream1
stream1 works fine
stream3 works fine

stderr (stream 2) has been disabled "permanently", even for the parent CMD.EXE shell.

You can avoid the "permanent" aspect by doing your redirection in stages:

@echo off
2>nul (
  3>nul (
    echo I want to see stream1
    1>&2 echo I don't want to see this stream2
    1>&3 echo I don't want to see this stream3
  )
)
echo stream1 works fine
1>&2 echo stream2 works fine
1>&3 echo stream3 works fine

And here is the desired output:

I want to see stream1
stream1 works fine
stream2 works fine
stream3 works fine

I don't really understand what is going on. But I have done some interesting experiments. Check out this thread: http://www.dostips.com/forum/viewtopic.php?f=3&t=2836&start=30

Addendum

As Erbert has discovered and shared in his comment, the fix is even easier if you just switch the order of the redirection - no need to stage it.

@echo off
3>nul 2>nul (
  echo I want to see stream1
  1>&2 echo I don't want to see this stream2
  1>&3 echo I don't want to see this stream3
)
echo stream1 works fine
1>&2 echo stream2 works fine
1>&3 echo stream3 works fine

Update 2012-04-03 I believe I finally understand the mechanics of Windows CMD.EXE redirection. I have a working theory that fully accounts for all the weird behavior, including why reversing the order prevents the "permanent" redirection. It also explains Aacini's observation that handle 3 appears to be connected to CON: (It isn't, it is actually undefined as per Windows documentation).

The key points are:

1 - Whenever a handle (stream) is redirected, the original definition is transferred to the first available undefined handle. Successive redirections are always carried out from left to right.

2 - When the redirection is over, the original definitions are normally restored. But if there is a chain of redirections, then the restoration is only done 1 level deep. This is the source of the "permanent" redirection.

Edit 2014-12-19: Put another way, the restoration appears to be done using a queue structure (FIFO - First In First Out), when it should have been implemented as a stack (LIFO - Last In First Out).

3 - When CMD.EXE carries out the redirection, it saves the current definition in the undefined handle first, then it redirects the first handle. If the first handle is redirected to the originally undefined handle, then it is effectively redirected to its original definition! That is why echo hello 1>&3 outputs to the console.

The full theory and test cases are available in two consecutive posts at http://www.dostips.com/forum/viewtopic.php?p=14612#p14612.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 3
    Thanks, that worked, +1 from me! But I have experimented a bit myself, using the reversed order (3 before 2) seems to work and is easier than your example: "FILE.BAT 3>NUL: 2>&3". – Erbert Mar 26 '12 at 21:50
  • 1
    @Erbert - Good idea switching the order! `FILE.BAT 3>NUL 2>NUL` works as well. – dbenham Mar 26 '12 at 22:18
  • 4
    +5, (if I could), this is a really impressive analysis of the streaming mechanism and it wasn't very obviously how it works – jeb Apr 03 '12 at 17:17
  • I've found that analisis is not complete. The "reassigned" handle 3 is not just standard command output, it is an internal terminal output handle, because the command: `echo.123 >1.log 3>2.log` will show the terminal command prompt in the file `2.log`. So any attempt to resuse it will involve a mixed output with the terminal output. – Andry Apr 08 '20 at 09:30
  • 1
    @Andry - No, you did not fully understand my answer. If you did then you would understand your behavior. First the existing value (console) in 1 is saved in 3 and then 1 is directed to 1.log. Then the existing value (console) in 3 is saved in 4 and then 3 is redirected to 2.log. Your command executes and 123 is written to 1.log. The command terminates and 1 is restored to value in 3 (2.log), and 3 is restored to value in 4 (console). So from this point forward anything sent to 1 is written to 2.log, and anything sent to 3 is written to the console. – dbenham Apr 08 '20 at 12:19
  • 1
    @Andry - As I stated in my answer, handle 3 is truly undefined until you perform some redirection. It is not related to the console (terminal), – dbenham Apr 08 '20 at 12:20
  • @dbenham This does not explain why handle 3 contains a terminal command prompt string as an output. The only explanation is that the stdout handle saved in the 3 is not the original stdout. – Andry Apr 08 '20 at 13:35
  • @Andry - I'm not seeing why you think the theory does not explain the results. I've run tests with the command you have given, and all the output is exactly as my theory predicts. If you still don't understand, then ask your own StackOverflow question with your exact script, actions taken, and example output. Or you could start a SO chat or ask a question on DosTips.com, either of which is more conducive to a back and forth "conversation" – dbenham Apr 08 '20 at 14:39
  • @dbenham May be because your tests are not complete? I am not arguing with you about your theory. There is nothing wrong with it. But examples demonstrating usage of the saved handle is not quite correct because suggests the saved stdout handle as an original handle which is not the fact. I have tested it in the Windows 7 and it makes the output mixed with the terminal output. – Andry Apr 08 '20 at 15:12
  • @Andry - I executed additional ECHO commands after the first command finished, and all output was as expected by my theory. I don't see what other tests are to be run. At start 1 = console, 3 is undefined, and 4 is undefined. After first redirection 1 = 1.log and 3 = console. After second redirection 3 = 2.log and 4 = console. 123 is written to 1.log. After first restore 1 = 2.log and 3 = undefined. After second restore 3 = console and 4 = undefined. From now on, all stdout is written to 2.log until cmd session is terminated. That explains all output that I see. – dbenham Apr 08 '20 at 17:07
  • @Andry - If you see something not explained by above then PLEASE post a question or start a chat. – dbenham Apr 08 '20 at 17:09
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211239/discussion-between-andry-and-dbenham). – Andry Apr 08 '20 at 17:22
  • @dbenham - please check my post https://www.dostips.com/forum/viewtopic.php?p=62428#p62428 – lockedscope Jul 17 '20 at 19:17
4

I apologize for post this as an answer instead of a comment, but my "comment" is too large...

In the MS-DOS standard, all running programs have open these Standard Handles: 0-STDIN (keyboard), 1-STDOUT (screen), 2-STDERR (screen), 3-STDAUX (serial port) and 4-STDPRN (printer). Although Windows documentation clearly indicate that handles 3-9 are undefined, handle 3 have a special treatment by CMD.EXE. I have three reasons to think this:

1- Handle 3 is connected to CON: device (keyboard for input, screen for output); handles 4-9 does not:

C>ver

Microsoft Windows XP [Version 5.1.2600]

C>echo To handle 3 >&3
To handle 3

C>echo To handle 4 >&4
The handle could not be duplicated
during redirection of handle 1.

C>set /P var=From handle 3: <&3
From handle 3: Value entered in keyboard

C>echo %var%
Value entered in keyboard

C>set /P var=From handle 4: <&4
The handle could not be duplicated
during redirection of handle 0.

2- The strange behavior of handle 3 stated in the present topic, that was solved in two differents ways. I discovered that if handles 0, 1 or 2 are redirected with handle 3 (and possibly handles 4-9), the redirection of handles 0, 1 or 2 becomes "permanent"; this behaviour doesn't happens if the handle 0, 1 or 2 are the last handle(s) in the list of redirections that include handle 3. This problem is entirely avoided if handles 0, 1 or 2 are redirected with handles 4-9 in any order, but not handle 3.

3- The results obtained with my TypeOfHandle.com program. This program is a pure MS-DOS executable file that check the handle given in its parameter and return via errorlevel a value of 3 if the handle is connected to the CONsole device, or a value of 128 if the handle is redirected to a disk file. These are the results:

C>typeofhandle 0

C>echo %errorlevel%
3

C>typeofhandle 0 < anyFile.txt

C>echo %errorlevel%
128

C>typeofhandle 1

C>echo %errorlevel%
3

C>typeofhandle 1 > anyFile.txt

C>echo %errorlevel%
128

C>typeofhandle 3

C>echo %errorlevel%
0

C>typeofhandle 3 <&3 anyFile.txt

C>echo %errorlevel%
0

C>typeofhandle 3 >&3 anyFile.txt

C>echo %errorlevel%
0

Handles 3-9 behaves strange in other aspect:

The results obtained with my SetFilePointer.com program. Although handles 3-9 may be used in a Batch file to achieve input/output from/to several files at once, such mechanism only allows sequential access because my SetFilePointer program can't move the File Pointer of handles 3-9. SetFilePointer program correctly works on handles 0, 1 and 2; this feature allows to write a complete Relational Database application in Batch. This topic is described in detail at this post

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Thanks. I didn't quite get all that, but that's OK. This trick seems to make handle 4 behave normally. (ECHO This is 4 1>&4) 3>NUL: DOS programs run under NTVDM, who might have own rules. – Erbert Mar 27 '12 at 22:55
  • Or maybe not, if I run "FILE.BAT 3>NUL:", 4 will redirect the same place as 3. – Erbert Mar 27 '12 at 22:57
  • 1
    @Aacini - Good evidence for Windows behavior, but the theory is not quite correct. See my updated answer for an explanation and link to test cases. – dbenham Apr 03 '12 at 15:05
  • @Aacini - please check my post https://www.dostips.com/forum/viewtopic.php?p=62428#p62428 – lockedscope Jul 17 '20 at 19:17
0

I think the answer may simply be to use handles 5-7, which you define by assigning them to your desired files as per the following:

5>"%tmp%\MyFileX.txt" 
6>"%tmp%\MyFileX.txt" 

Thereby one can direct the output to either file using 1>&5 or 1>&6 redirection.

Abhishek Dutt
  • 1,308
  • 7
  • 14
  • 24
-2

The problem is with 3>&2. File descriptor 3 isn't valid, and it appears to upset Windows in some way. Leave it off, you don't need it.

See Microsoft's documentation (archived) for the full treatment.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    It says 3-9 are supported. I want to have 3 different output on my batch: @ECHO OFF ECHO This is 1 ECHO This is 2 1>&2 ECHO This is 3 1>&3 And then when I run that and want to hide both 2 and 3 ("FILE.BAT 2>NUL: 3>&2") it will be set permanently. – Erbert Mar 26 '12 at 19:30
  • @Erbert, it says 3-9 are undefined and depend on the tool. Unless the tool specifically documents how it will react to a particular file handle redirection, don't do it. And I don't quite understand what result you're trying to get - what do you mean by "3 different output"? – Mark Ransom Mar 26 '12 at 19:35
  • But as Attila pointed out it's CMD's job to handle to the handles. My batch file is using 3 output handles. – Erbert Mar 26 '12 at 19:45
  • @MarkRansom - The documentation only mentiones that it is defined by the application, but does not say anything about what happens when the application does not associate anything to a file handle above 2. I would expect it not to be a problem if I specify the redirection of fh 3, but the app does not read/write anything from/to it. – Attila Mar 26 '12 at 20:07
  • Right, and this happens even if a batch file is writing to 3. So his answer does not work. – Erbert Mar 26 '12 at 20:10
  • @Erbert, you still haven't explained to me why you're trying to redirect handle 3. It makes no sense to me. – Mark Ransom Mar 26 '12 at 20:23
  • Because programs or batch files might output to handle 3. – Erbert Mar 26 '12 at 21:05
  • @Erbert, since file handle 3 isn't assigned to anything by default there's no reason for a program to write to it. – Mark Ransom Mar 26 '12 at 21:10
  • 1
    But I just wrote an example of how a batch file can write to handle 3. I'm sure some programs do it as well. – Erbert Mar 26 '12 at 21:17
  • @Erbert, just because the syntax supports it doesn't mean it's a good idea. There appears to be a bug in Windows, and it's a very easy bug to avoid. I suggest avoiding it. – Mark Ransom Mar 26 '12 at 21:23
  • @Erbert: My guess is, handle 3 "is defined by" and "specific to" CMD. – Andriy M Mar 27 '12 at 05:45
  • Here is one practical reason to write to 3: You have a script that conditionally writes many lines to 1 of 2 output files, depending on the content of each line. You could simply use `>>` and append each line to the appropriate file, but it is inefficient (slow) to repeatedly open and close the output file for each write. Much more efficient to call a routine with `3>file2 1>file1`, and then within the routine some lines are written normally, others are redirected using `1>&3`. – dbenham Jun 10 '13 at 11:31
  • 1
    It is misleading to say these descriptors are `not valid`. The documentation you linked says they are `UNDEFINED`. The string "`valid`" does not appear on that documentation page. So they are invalid only if the assumption that 'invalid' contains 'undefined' holds. – n611x007 May 21 '15 at 12:04