그게 버그일까요? 실행 시 현재 cmd 창 즉시 닫기: move nul 2>&0

그게 버그일까요? 실행 시 현재 cmd 창 즉시 닫기: move nul 2>&0

결국 나는 사용한다move nul 2>&0내 스크립트에서는 cmd 창의 현재를 "갑자기" 닫아 실행 중인 박쥐를 즉시 중단/닫습니다.

대본에서는 자살처럼 작동한다고 말할 수는 없지만 보통 그렇게 부릅니다.

실제로 이로 인해 현재 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 창"이라는 문구 때문에 어려움을 겪고 있습니다. 무슨 뜻인지 잘 모르겠습니다. 내 생각에는 두 가지 서로 다른 개념을 결합하고 있습니다.

  • 콘솔 프로세스가 있습니다. 터미널과 유사하지만 완전히 동일하지는 않습니다.
  • 그리고 콘솔 창 내에서 실행되는 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 = external이라는 사실은 내부 프로세스가 충돌했기 때문에 내부 환경이 손실되었음을 증명합니다. 그런 다음 EXIT 명령을 실행하면 외부 cmd.exe 프로세스가 종료되고 콘솔이 닫힙니다.

이제 명령이 cmd.exe와 충돌하는 이유를 살펴보겠습니다. MOVE명령이나 장치 사용에는 특별한 것이 없습니다 nul. 중요한 점은 cmd.exe가 stdin으로 리디렉션된 후 stderr에 오류 메시지를 쓰려고 한다는 것입니다. 분명히 작동할 수 없으므로 쓰기가 실패합니다. 이것이 cmd.exe를 충돌시키는 원인이 됩니다.

를 통해 0으로 나누는 오류로도 동일한 효과를 얻을 수 있습니다 SET /A 1/0 2>&0.

리디렉션이 실제로 성공한다는 점에 유의하는 것이 중요합니다. 리디렉션은 stdin이 출력을 받아들일 수 없다는 점에 신경 쓰지 않고 맹목적으로 리디렉션을 수행합니다. cmd.exe 오류 쓰기 루틴이 실제로 리디렉션된 stderr에 쓰려고 시도하는 경우에만 오류가 발생합니다.

stderr에 쓰지 않는 명령을 단순히 리디렉션하면 리디렉션이 성공한다는 것을 쉽게 입증할 수 있습니다. 예를 들어 echo Hello world 2>&0무의미한 리디렉션을 수행하고 메시지를 stdout에 성공적으로 기록합니다.

DosTips 어딘가에 cmd.exe가 I/O 오류를 처리하는 방법을 조사한 게시물이 있습니다. 그 게시물을 찾을 수 있었으면 좋겠습니다. 내 테스트에는 stdout 또는 stderr을 이동식 장치로 리디렉션한 다음 일시 중지하는 작업이 포함된 것 같습니다. 일시 중지하는 동안 장치를 제거한 다음 계속합니다. 그런 다음 stdout 또는 stderr를 통해 누락된 장치에 쓰려고 할 때의 동작을 관찰했습니다. 내가 기억하는 바에 따르면 stderr에 대한 모든 쓰기 실패는 즉시 cmd.exe와 충돌합니다.

이것은 버그입니까 아니면 설계 결함입니까? 확실하지 않다. 오류 보고가 실패할 경우 가장 안전한 방법은 종료하는 것이라고 주장할 수도 있습니다. 그러나 stdout에 쓰기가 실패하면 오류 메시지나 오류가 반환되지 않기 때문에 이것이 계획된 "기능"이라고 확신하지 않습니다! 출력은 단순히 에테르 속으로 사라지고, cmd.exe는 마치 아무 일도 일어나지 않은 것처럼 태평하게 계속됩니다. stdout에 쓸 때 배치가 실패를 감지하는 것은 불가능합니다. 나는 그것이 끔찍하다고 생각합니다. 나는 cmd.exe 개발자가 그런 가능성을 전혀 고려하지 않았다고 가정할 수 있습니다. 그래서 그것이 사실이라면 stderr 실패가 충돌한다는 사실은 쉽게 (행복한?) 사고가 될 수 있습니다.

stdout과 stderr 동작 사이에는 몇 가지 다른 차이점이 있었습니다. 둘 다 버퍼링되어 있지만 버퍼 오버플로가 있는 경우 다르게 동작했습니다. 그 차이점이 무엇인지 기억할 수 있었으면 좋겠습니다 :-(

업데이트

내가 조사한 내용 중 일부를 다음에서 찾았습니다.https://www.dostips.com/forum/viewtopic.php?t=6881

stdout에 쓰는 것은 위의 글이 암시하는 것보다 조금 더 복잡합니다. Cmd.exe에는 stdout에 쓰기를 시도하는 여러 내부 루틴이 있습니다. 예를 들어:

  • ECHO 명령
  • SET /P 메시지(입력 프롬프트)
  • 명령줄 프롬프트 및 배치 명령줄 에코(ECHO가 켜져 있는 경우)
  • DIR 등의 명령 출력

stdout에 쓰는 이러한 진입점 중 일부는 쓰기 실패 시 자체 동작을 가질 수 있습니다. 위의 링크에서는 예를 들어 ECHO와 SET /P의 차이점을 설명합니다.

확실하지는 않지만 stderr에 대한 오류 메시지는 다르다고 생각합니다. 나는 모든 오류 보고가 쓰기 오류가 있을 때 충돌하는 단일 내부 루틴을 통해 전달된다고 생각합니다. 위의 링크는 실제로 이것을 조사하지 않습니다. 나는 여전히 I/O 오류(및 버퍼링 문제)를 더 잘 조사한 훨씬 이후의 게시물을 찾고 있습니다.

관련 정보