最终,我move nul 2>&0
在我的脚本中使用“突然”关闭当前的 cmd 窗口,从而立即中止/关闭正在运行的 bat。
我不能说它就像剧本中的自杀一样,但我通常这样称呼它。
事实上,这会导致在当前 cmd 窗口中扩展/达到效果的自动终止。
这不仅仅是关闭/结束正在运行的球棒。
基本上用于一些批处理,其中变量的值"%cmdcmdline%"
通过单击调用来执行响应,而不是简单地关闭蝙蝠,也关闭通过单击蝙蝠激活/加载的窗口。
我想知道的是:
- 什么解释了这种行为?
- 它是一个错误吗?
- 将来它的行为可能不一样吗?
一些代码示例:
@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
我对您的短语“当前 cmd 窗口”感到困惑-不确定您的意思。在我看来,您正在结合两个不同的概念
您的命令正在使 cmd.exe 进程崩溃,并且您的控制台进程完全关闭,因为它不再有在其中运行的进程。
如果您在额外的子 cmd.exe 进程中运行命令,这很容易证明 - 子 cmd.exe 崩溃,但父进程仍然有效,因此控制台窗口也保持运行。这是一个从控制台中运行的全新 cmd.exe 进程开始的示例。
最后context=outer证明了内部环境已经丢失,原因是内部进程崩溃了。如果我随后发出 EXIT 命令,则外部 cmd.exe 进程终止并且控制台关闭。
现在了解为什么您的命令会导致 cmd.exe 崩溃。
MOVE
您对命令或设备的使用没有什么特别之处nul
。关键是 cmd.exe 在重定向到 stdin 后尝试向 stderr 写入错误消息。显然这不起作用,所以写入失败 - 这是导致 cmd.exe 崩溃的触发器。用零误差除法可以达到同样的效果
SET /A 1/0 2>&0
。重要的是要注意重定向实际上是成功的。重定向不关心标准输入不能接受输出,它盲目地执行重定向。仅当 cmd.exe 错误写入例程尝试实际写入重定向的 stderr 时才会发生故障。
如果您只是重定向一个不写入 stderr 的命令,则很容易证明重定向成功。例如,
echo Hello world 2>&0
执行无意义的重定向并将消息成功写入标准输出。在 DosTips 的某个地方,我有一些帖子调查了 cmd.exe 如何处理 I/O 错误。我希望我能找到那个帖子。我相信我的测试涉及将 stdout 或 stderr 重定向到可移动设备,然后暂停。在暂停期间,我会移除设备,然后继续。然后,当我尝试通过 stdout 或 stderr 写入丢失的设备时,我会观察该行为。据我记得,所有对 stderr 的失败写入都会立即使 cmd.exe 崩溃。
这是错误还是设计缺陷?没有把握。有人可能会争辩说,如果错误报告失败,也许最安全的做法是终止。但我不相信这是计划中的“功能”,因为当写入标准输出失败时,没有错误消息或错误返回什么!输出只是消失在以太中,cmd.exe 愉快地继续,好像没有发生任何不好的事情。写入标准输出时,批处理不可能检测到故障。我觉得那太残忍了。我只能假设 cmd.exe 的开发人员从来没有考虑过这种可能性。因此,如果这是真的,那么 stderr 故障崩溃的事实很容易成为(快乐?)事故。
stdout 和 stderr 行为之间还有一些其他差异。两者都是缓冲的,但如果存在缓冲区溢出,它们的行为会有所不同。我希望我能记住那个区别是什么:-(
更新
我在https://www.dostips.com/forum/viewtopic.php?t=6881找到了我的一些调查
写入标准输出比我上面的文章所暗示的要复杂一些。Cmd.exe 有多个尝试写入标准输出的内部例程。例如:
当写入失败时,其中一些写入标准输出的入口点可能有自己的行为。例如,我上面的链接描述了 ECHO 和 SET /P 之间的差异。
我不确定,但我相信 stderr 的错误消息是不同的。我相信所有错误报告都是通过一个内部例程进行的,当出现写入错误时,该例程会崩溃。我上面的链接并没有真正对此进行调查。我仍在寻找更好地调查 I/O 错误(和缓冲问题)的更晚的帖子