Would that be a bug? Immediate closing of the current cmd window when executing: move nul 2>&0

I struggle with your phrase "current cmd window" - not sure what you mean. In my mind you are combining two distinct concepts

  • There is the console process - analogous to, but not quite the same as a terminal
  • And there is the cmd.exe process that is executing within the console window

Your command is crashing the cmd.exe process, and your console process cleanly shuts down because it no longer has a process running within it.

This is easy to prove if you run your command within an extra child cmd.exe process - the child cmd.exe crashes, but the parent remains valid, so the console window also remains running. Here is an example starting from a brand new cmd.exe process running in the console.

Microsoft Windows [Version 10.0.18363.1256]
(c) 2019 Microsoft Corporation. All rights reserved.

P:\>set context=outer

P:\>cmd
Microsoft Windows [Version 10.0.18363.1256]
(c) 2019 Microsoft Corporation. All rights reserved.

P:\>set context=inner

P:\>move nul 2>&0

P:\>set context
context=outer

P:\>

The fact that context = outer at the end proves that the inner environment has been lost, the reason being that the inner process has crashed. If I then issue the EXIT command, then the outer cmd.exe process terminates and the console closes.

Now onto why your command crashes cmd.exe. There is nothing special about your use of the MOVE command or the nul device. The critical piece is that cmd.exe is attempting to write an error message to stderr after it has been redirected to stdin. Obviously that cannot work, so the write fails - this is the trigger that causes cmd.exe to crash.

The same effect can be achieved with division by zero error via SET /A 1/0 2>&0.

It is important to note that the redirection actually succeeds. Redirect doesn't care that stdin cannot accept output, it blindly carries out the redirection. The failure occurs only when the cmd.exe error writing routine tries to actually write to the redirected stderr.

It is easy to demonstrate that the redirection succeeds if you simply redirect a command that doesn't write to stderr. For example, echo Hello world 2>&0 performs the nonsensical redirection and successfully writes the message to stdout.

Somewhere on DosTips I have some posts where I investigated how cmd.exe handles I/O errors. I wish I could find that post. I believe my test involved redirecting stdout or stderr to a removable device, and then pausing. During the pause I would remove the device, and then continue. I would then observe the behavior when I attempted to write to the missing device via stdout or stderr. From what I remember, all failed writes to stderr immediately crash cmd.exe.

Is this a bug or design flaw? Not sure. One could argue that perhaps the safest thing to do if error reporting fails is to terminate. But I'm not convinced that was a planned "feature" because when writes to stdout fail, there is no error message or error returned what-so-ever! The output simply disappears into the ether, cmd.exe blithely carries on as if nothing bad happened. It is impossible for batch to detect failures when writing to stdout. I find that atrocious. I can only assume the developers of cmd.exe never bothered to consider that possibility. So if that is true, then the fact that stderr failures crash could easily be a (happy?) accident.

There were some other differences between stdout and stderr behavior. Both are buffered, but they behaved differently if there was a buffer overflow. I wish I could remember what that difference was :-(

Update

I found some of my investigations at https://www.dostips.com/forum/viewtopic.php?t=6881

Writing to stdout is a bit more complicated then my writeup above implies. Cmd.exe has multiple internal routines that attempt to write to stdout. For example:

  • ECHO command
  • SET /P message (prompt for input)
  • The command line prompt and echoing of the batch command line (when ECHO is ON)
  • Output of commands like DIR, etc.

Some of these entry points that write to stdout may have their own behavior when there is a write failure. My link above describes differences between ECHO and SET /P for example.

I'm not certain, but I believe error messages to stderr are different. I believe all error reporting is funneled through a single internal routine that crashes when there is a write error. My link above doesn't really investigate this. I'm still looking for the much later posts that better investigated the I/O errors (and buffering issues)