Eventualmente, eu uso move nul 2>&0
em meus scripts para fechar "abruptamente" a corrente da janela cmd e, assim, abortar/fechar imediatamente o bat em execução.
Não posso dizer que funciona como um suicídio no roteiro, mas costumo chamar assim.
Na verdade, isso resulta em um auto-kill que estende/alcança o efeito também na janela cmd atual.
É algo diferente de apenas fechar/terminar um morcego em execução.
Basicamente uso para alguns batches onde o valor da variável "%cmdcmdline%"
para uma resposta executando invocado por click, ao invés de simplesmente fechar o bat, fechando também a janela que foi ativada/carregada clicando no bat.
O que eu me pergunto é:
- O que explica esse comportamento?
- É um bug?
- No futuro pode não se comportar da mesma forma?
Alguns exemplos de códigos:
@echo off
title <nul
title to kill or not to kill?
mode 50,05
echo\%cmdcmdline%|find "%~0" >nul && (
echo\
echo\ so sorry bro, I'll kill myself
echo\ and this CMD.exe window too!
timeout 5 /nobreak
move nul 2>&0
)
echo/ will run this code bro!
echo/
echo/ keep itself alive: %date% %time:~0,5%
echo/
pause
Eu luto com sua frase "janela cmd atual" - não tenho certeza do que você quer dizer. Na minha cabeça você está combinando dois conceitos distintos
Seu comando está travando o processo cmd.exe e seu processo de console é encerrado corretamente porque não tem mais um processo em execução dentro dele.
Isso é fácil de provar se você executar seu comando em um processo cmd.exe filho extra - o cmd.exe filho falha, mas o pai permanece válido, então a janela do console também permanece em execução. Aqui está um exemplo a partir de um novo processo cmd.exe em execução no console.
O fato de contexto = externo no final prova que o ambiente interno foi perdido, a razão é que o processo interno caiu. Se eu emitir o comando EXIT, o processo cmd.exe externo será encerrado e o console será fechado.
Agora, por que seu comando trava cmd.exe. Não há nada de especial no uso do
MOVE
comando ou donul
dispositivo. A parte crítica é que o cmd.exe está tentando escrever uma mensagem de erro para stderr depois de ter sido redirecionado para stdin. Obviamente, isso não pode funcionar, então a gravação falha - este é o gatilho que faz com que o cmd.exe falhe.O mesmo efeito pode ser obtido com a divisão por erro zero via
SET /A 1/0 2>&0
.É importante observar que o redirecionamento realmente é bem-sucedido. O redirecionamento não se importa que o stdin não possa aceitar a saída, ele realiza o redirecionamento cegamente. A falha ocorre somente quando a rotina de gravação de erro cmd.exe tenta realmente gravar no stderr redirecionado.
É fácil demonstrar que o redirecionamento é bem-sucedido se você simplesmente redirecionar um comando que não grava em stderr. Por exemplo,
echo Hello world 2>&0
executa o redirecionamento sem sentido e grava com êxito a mensagem em stdout.Em algum lugar no DosTips, tenho alguns posts onde investiguei como o cmd.exe lida com erros de E/S. Eu gostaria de encontrar esse post. Acredito que meu teste envolveu redirecionar stdout ou stderr para um dispositivo removível e, em seguida, pausar. Durante a pausa, eu removia o dispositivo e continuava. Eu observaria o comportamento quando tentasse gravar no dispositivo ausente via stdout ou stderr. Pelo que me lembro, todas as gravações com falha no stderr travam imediatamente o cmd.exe.
Isso é um bug ou falha de projeto? Não tenho certeza. Pode-se argumentar que talvez a coisa mais segura a fazer se o relatório de erros falhar é encerrar. Mas não estou convencido de que foi um "recurso" planejado porque quando as gravações em stdout falham, não há mensagem de erro ou erro retornado de qualquer maneira! A saída simplesmente desaparece no éter, cmd.exe continua alegremente como se nada de ruim tivesse acontecido. É impossível para o lote detectar falhas ao gravar em stdout. Acho isso atroz. Só posso supor que os desenvolvedores do cmd.exe nunca se preocuparam em considerar essa possibilidade. Então, se isso for verdade, então o fato de as falhas do stderr falharem poderia facilmente ser um (feliz?) acidente.
Houve algumas outras diferenças entre o comportamento stdout e stderr. Ambos são armazenados em buffer, mas se comportam de maneira diferente se houver um estouro de buffer. Eu gostaria de lembrar qual era essa diferença :-(
Atualizar
Encontrei algumas das minhas investigações em https://www.dostips.com/forum/viewtopic.php?t=6881
Escrever para stdout é um pouco mais complicado do que o meu writeup acima implica. Cmd.exe tem várias rotinas internas que tentam gravar em stdout. Por exemplo:
Alguns desses pontos de entrada que gravam em stdout podem ter seu próprio comportamento quando há uma falha de gravação. Meu link acima descreve as diferenças entre ECHO e SET /P, por exemplo.
Não tenho certeza, mas acredito que as mensagens de erro para stderr sejam diferentes. Acredito que todos os relatórios de erros são canalizados por meio de uma única rotina interna que trava quando há um erro de gravação. Meu link acima realmente não investiga isso. Ainda estou procurando as postagens muito posteriores que investigaram melhor os erros de E/S (e problemas de buffer)