Page 1 of 1
programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 23 Aug 2014 15:22
by dbenham
I found this amazing/surprising feature at
http://stackoverflow.com/q/25444765/1012053. Maybe someone can find a use for it.
Update - Scroll down to the 5th post to see how it can be used to cleanly exit from batch processing, regardless how many CALLs have been issued.Here is a very simple TEST.BAT:
Code: Select all
@echo off
:loop
echo before
cmd /c exit -1073741510
echo after
echo(
goto loop
The Ctrl-C exit code returned from CMD /C is interpreted the same as if someone pressed the Ctrl-C key. The same effect is achieved with a return value of 3221225786.
Here is sample output with 2 iterations, first entering "n", then "y":
Code: Select all
C:\test>test
before
^CTerminate batch job (Y/N)? n
after
before
^CTerminate batch job (Y/N)? y
C:\test>
The ^C that displays can be hidden by redirecting stderr to nul. It is not the actual Ctrl-C character.
Code: Select all
@echo off
:loop
echo before
cmd /c exit -1073741510 2>nul
echo after
echo(
goto loop
sample output:
Code: Select all
C:\test>test
before
Terminate batch job (Y/N)? n
after
before
Terminate batch job (Y/N)? y
C:\test>
The ^C display is not the actual Ctrl-C character. It is actually a caret, followed by C, which is displayed on stderr when CMD.EXE detects Ctrl-C. That can be seen by redirecting stderr to stdout, and capturing the value with FOR /F.
Code: Select all
@echo off
setlocal enableDelayedExpansion
for /f %%C in ('cmd /c exit -1073741510 2^>^&1') do (
set "str=%%C"
echo str[0]=!str:~0,1!
echo str[1]=!str:~1,1!
)
output:
Dave Benham
Re: programmatically "press" Ctrl-C
Posted: 24 Aug 2014 04:28
by aGerman
Hi Dave
Thath's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value
I tried a few other values found at the
related MSDN site yet without success ...
Regards
aGerman
Re: programmatically "press" Ctrl-C
Posted: 24 Aug 2014 06:08
by dbenham
aGerman wrote:That's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value
I'm not so sure... It is the error code that indicates Ctrl-C termination.
aGerman wrote:I tried a few other values found at the
related MSDN site yet without success ...
I'm curious - just what kind of effect were you expecting for other return codes to indicate "success"?
Dave Benhaqm
Re: programmatically "press" Ctrl-C
Posted: 24 Aug 2014 08:18
by aGerman
dbenham wrote:aGerman wrote:That's quite interesting even if I believe it must be some kind of a bug. I can't believe it was intention to signal that message via return value
I'm not so sure... It is the error code that indicates Ctrl-C termination.
I'm also not sure, but the description says "The application terminated as a result of a CTRL+C". Since you never pressed CTRL+C it's at least a bit strange from my point of view.
dbenham wrote:I'm curious - just what kind of effect were you expecting for other return codes to indicate "success"?
I actually didn't expect that anything else could affect the batch window because I assume it's just undefined behavior.
I tried with values like STATUS_FATAL_APP_EXIT and STATUS_PROCESS_IS_TERMINATING. I thought it would let the process freeze or whatever ...
Regards
aGerman
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 24 Aug 2014 09:39
by dbenham
This feature is actually quite useful
It can be used to cleanly exit all batch processing, regardless how many CALLs have been issued.
In past threads, jeb has shown how a fatal syntax error can be used to exit batch processing while within a CALL (I failed to find a link). But that technique can corrupt the environment because the implicit ENDLOCAL mechanism does not work properly: See
viewtopic.php?p=9199#p9199Here is a TEST.BAT that demonstrates how the programmatic Ctrl-C "press" can be used to cleanly exit from batch processing while within a CALL.
Code: Select all
@echo off
setlocal
set test=AFTER 1st SETLOCAL
setlocal
set test=AFTER 2nd SETLOCAL
call :sub1
echo returning from main NEVER REACHED
exit /b
:sub1
setlocal
set test=AFTER sub1 1st SETLOCAL
setlocal
set test=AFTER sub1 2nd SETLOCAL
call :sub2
echo returning from sub1 NEVER REACHED
exit /b
:sub2
setlocal
set test=AFTER sub2 1st SETLOCAL
setlocal
set test=AFTER sub2 2nd SETLOCAL
set test
call :ExitBatch
echo returning from sub2 NEVER REACHED
exit /b
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs
if not exist "%temp%\ExitBatchYes.txt" call :buildYes
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
:CtrlC
cmd /c exit -1073741510
:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul ExitBatchYes.txt >nul
for /f "delims=(/ tokens=2" %%Y in (
'"copy /-y nul ExitBatchYes.txt <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>ExitBatchYes.txt
popd
exit /b
sample run output:
Code: Select all
C:\test>test
test=AFTER sub2 2nd SETLOCAL
C:\test>set test
Environment variable test not defined
The entire CALL stack of SETLOCAL has been properly handled, so variable test is no longer defined upon batch termination. If a fatal syntax error were used instead of the :ExitBatch routine, then test would still be defined as AFTER sub2 2nd SETLOCAL upon batch termination.
The routine can be put into a stand-alone script named ExitBatch.bat and placed somewhere within the PATH. Then it can be conveniently used as needed by any batch script.
Code: Select all
@echo off
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs
if not exist "%temp%\ExitBatchYes.txt" call :buildYes
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1
:CtrlC
cmd /c exit -1073741510
:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul ExitBatchYes.txt >nul
for /f "delims=(/ tokens=2" %%Y in (
'"copy /-y nul ExitBatchYes.txt <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>ExitBatchYes.txt
popd
exit /b
Dave Benham
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 24 Aug 2014 12:41
by einstein1969
@Dave
I don't know if the jeb method is the same for exit from a infinite for loop...
here jeb use the HALT method .
Here suggest to use.
this is the method you mentioned?
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 25 Aug 2014 05:32
by jeb
@Dave
Very nice technic
I tried a bit to use CTRL-C for another cmd.exe thread, but currently all my attempts fail.
I tried it with pipes and also with start /b, but I haven't an idea how to transfer the CTRL-C to different cmd instance.
jeb
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 25 Aug 2014 06:10
by dbenham
jeb wrote:I tried a bit to use CTRL-C for another cmd.exe thread, but currently all my attempts fail.
I tried it with pipes and also with start /b, but I haven't an idea how to transfer the CTRL-C to different cmd instance.
Very mysterious
I also failed with CMD /C and pipes. Of course, if one fails, than so too should the other. But I succeeded with START /B /WAIT.
Edit: Wrong! START /B /WAIT Fails as well Here is TEST2.BAT that launches my TEST.BAT from prior post in various ways.
Code: Select all
@echo off
echo(
echo launching via CMD /C ...
cmd /c test.bat
echo Returned %errorlevel%
echo(
echo launching via pipe ...
echo OK | test.bat
echo Returned %errorlevel%
echo(
echo launching via START /B /WAIT ...
start "" /b /wait test.bat
echo Returned %errorlevel% NEVER REACHED
Sample output
Code: Select all
C:\test>test2
launching via CMD /C ...
test=AFTER sub2 2nd SETLOCAL
Returned 255
launching via pipe ...
test=AFTER sub2 2nd SETLOCAL
Returned 255
launching via START /B /WAIT ...
test=AFTER sub2 2nd SETLOCAL
C:\test>echo %errorlevel%
-1073741510
C:\test>
Why on earth do CMD /C and the pipe transform the ERRORLEVEL to 255
This is especially puzzling because CMD /C was used to "press" Ctrl-C in the first place
START /B /WAIT appears to work, but in reality it hasn't returned to the originating CMD session yet. Issuing EXIT returns and the calling script resumes.
Dave Benham
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 25 Aug 2014 16:08
by penpen
dbenham wrote:You can see that START /B /WAIT works, although I'm a bit surprised it does not prompt to see if you want to terminate or not.
Are you sure? Try 'exit'; this happens on WinXP home:
Code: Select all
Z:\>test2.bat
launching via CMD /C ...
Returned 255
launching via pipe ...
Returned 255
launching via START /B /WAIT ...
Z:\>exit
^CBatchvorgang abbrechen (J/N)? n
Returned -1073741510 NEVER REACHED
Z:\>
The same behaviour when using 'exit /B', but it changes the errorlevel, if you specify one:
Code: Select all
(...)
launching via START /B /WAIT ...
Z:\>exit /B 2
^CBatchvorgang abbrechen (J/N)? n
Returned 2 NEVER REACHED
Z:\>
penpen
Re: programmatically "press" Ctrl-C / Exit batch inside CALL
Posted: 25 Aug 2014 22:17
by dbenham
Thanks penpen. You are absolutely correct, and jeb was correct all along (of course). I've corrected my prior post.
Dave Benham