那會是個錯誤嗎?執行時立即關閉目前cmd視窗:move nul 2>&0

那會是個錯誤嗎?執行時立即關閉目前cmd視窗:move nul 2>&0

最終,我使用move nul 2>&0在我的腳本中「突然」關閉當前的cmd窗口,從而立即中止/關閉正在運行的bat。

我不能說這就像劇本中的自殺一樣,但我通常這麼稱呼它。

事實上,這會導致自動終止,並在目前的 cmd 視窗中擴展/達到效果。

它不僅僅是關閉/結束正在運行的球棒。

基本上用於一些批次,其中變數的值"%cmdcmdline%"透過執行點擊呼叫來回應,而不是簡單地關閉蝙蝠,也關閉透過點擊蝙蝠啟動/載入的視窗。

我想知道的是:

  1. 如何解釋這種行為?
  2. 這是一個錯誤嗎?
  3. 將來它的行為可能不會一樣嗎?

一些程式碼範例:

@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

答案1

我對你的短語“當前命令視窗”感到困惑 - 不知道你的意思。在我看來,你結合了兩個不同的概念

  • 有控制台進程 - 類似終端,但不完全相同
  • 控制台視窗中正在執行 cmd.exe 進程

您的命令使 cmd.exe 進程崩潰,並且您的控制台進程完全關閉,因為它不再有進程正在運行。

如果您在額外的子 cmd.exe 進程中執行命令,這一點很容易證明 - 子 cmd.exe 崩潰,但父進程仍然有效,因此控制台視窗也保持運行。下面是從控制台中執行的全新 cmd.exe 進程開始的範例。

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:\>

最後context=outer證明內部環境已經遺失,原因是內部進程崩潰了。如果我隨後發出 EXIT 命令,則外部 cmd.exe 進程將終止且控制台將關閉。

現在來看看為什麼你的指令會導致 cmd.exe 崩潰。您對MOVE命令或設備的使用沒有什麼特別的nul。關鍵是 cmd.exe 在重定向到 stdin 後嘗試向 stderr 寫入錯誤訊息。顯然這是行不通的,所以寫入失敗——這是導致 cmd.exe 崩潰的觸發器。

透過除以零誤差可以達到相同的效果SET /A 1/0 2>&0

需要注意的是,重定向實際上成功了。 Redirect 並不在乎 stdin 不能接受輸出,它只是盲目地執行重定向。只有當 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 有多個嘗試寫入標準輸出的內部例程。例如:

  • 回顯命令
  • SET /P 訊息(提示輸入)
  • 批次命令行的命令列提示和回顯(當ECHO為ON時)
  • DIR 等指令的輸出

當寫入失敗時,某些寫入 stdout 的入口點可能有自己的行為。例如,我上面的連結描述了 ECHO 和 SET /P 之間的差異。

我不確定,但我相信 stderr 的錯誤訊息是不同的。我相信所有錯誤報告都是透過一個內部例程傳遞的,當出現寫入錯誤時該例程會崩潰。我上面的連結並沒有真正調查這一點。我仍在尋找更晚的帖子來更好地調查 I/O 錯誤(和緩衝問題)

相關內容