Ctrl + C无法可靠地终止Windows批处理脚本

时间:2016-09-13 14:43:29

标签: windows batch-file cmd

我正在尝试编写一个批处理脚本,提示用户输入目录,并将多个文件从此目录复制到另一个目录。为此,我有一个简单的循环,使用标签和set /p进行输入。问题是按ctrl+c试图摆脱这个循环并不总是有效。

:checkloop

@set /p READMEPATH=Please enter the location of readme.txt: 

@if not exist "%READMEPATH%\README.txt" goto somethingmissing

@goto allfound

:somethingmissing
@echo Can't find readme in directory "%READMEPATH%"
@goto checkloop

:allfound

@echo Okay, found

示例输出类似于

Please enter the location of readme.txt:
Can't find readme in directory ""
Please enter the location of readme.txt: ^CCan't find readme in directory ""
Please enter the location of readme.txt: ^CCan't find readme in directory ""
Please enter the location of readme.txt: ^CCan't find readme in directory ""
Please enter the location of readme.txt: ^CCan't find readme in directory ""
Please enter the location of readme.txt: ^CCan't find readme in directory ""
Please enter the location of readme.txt: ^CTerminate batch job (Y/N)? y

重复按下ctrl + c,就像我按下回车一样,脚本继续运行,直到它最终运行。所需的尝试次数是可变的;有时它会立即起作用,有时2-3次,很少需要7次以上。

操作系统是Windows 10。

2 个答案:

答案 0 :(得分:2)

您可以检查是否定义了READMEPATH。

:checkloop
set "READMEPATH="
set /p READMEPATH=Please enter the location of readme.txt: 
if not defined READMEPATH exit /b

但是,这无法检测到按空格键CTRL-C和ENTER之间的区别。

答案 1 :(得分:1)

这是基于Dave Benham编写的getKey 1.3版,最初发布于Read key presses via REPLACE - New functions :getKey, :getAnyKey, :getMaskedInput

更复杂的批处理,但作为概念证明,它区分CTRL + C和ENTER。

@echo off
setlocal

for /F %%# in ('forfiles /m "%~nx0" /c "cmd /c echo 0x03"') do set "CTRLC=%%#" & rem capture CTRL-C char
for /F %%# in ('copy /Z "%~dpf0" NUL') do set "CR=%%#"                         & rem capture carriage return char
for /F %%# in ('"prompt $H&for %%@ in (1) do rem"') do set "BS=%%#"                                         & rem capture backspace char
for /F "tokens=1,2 delims=#" %%# in ('"prompt #$H#$E# & echo on & for %%@ in (1) do rem"') do set "DEL=%%#" & rem capture DEL char

:checkloop
cls & set "READMEPATH="
<nul set/P "=Please enter the location of readme.txt: " 

:getPath
call :getKey key

if "%key%" equ "%CTRLC%" exit/B & rem or whatever you wanna do
if "%key%" equ "%CR%" goto:done 

if "%key%" equ "%BS%" (
  <nul set/P=%DEL%
  set "READMEPATH=%READMEPATH:~0,-1%"
) else (
  <nul set/P=%key%
  set "READMEPATH=%READMEPATH%%key%"
)

goto getPath

:done
if not defined READMEPATH exit/B
@if not exist "%READMEPATH%\README.txt" goto somethingmissing

@goto allfound

:somethingmissing

echo(&echo( Can't find readme in directory "%READMEPATH%"
pause
@goto checkloop

:allfound

@echo Okay, found
endlocal
exit/B

::getKey  KeyVar  [ValidVar]
::
:: Read a keypress representing a character between 0x00 and 0xFF and store the
:: value in variable KeyVar. Null (0x00), LineFeed (0x0A), and Carriage Return
:: (0x0D) will result in an undefined KeyVar. On Windows 10, Ctrl-Z (0x1A) will
:: also result in an undefined KeyVar. The simplest way to get an undefined
:: KeyVar is to press the [Enter] key.
::
:: The optional ValidVar variable defines the values that will be accepted.
:: If not given or not defined, then all characters are accepted. If given
:: and defined, then only characters within ValidVar are accepted. The first
:: character within ValidVar should either be 0, meaning ignore undefined KeyVar,
:: or 1, meaning accept undefined KeyVar. The remaining characters represent
:: themselves. For example, a ValidVar value of 0YNyn will only accept upper
:: or lower case Y or N. A value of 1YNyn will additionally accept [Enter] etc.
::
:: Any value (except null) may be entered by holding the [Alt] key and pressing
:: the appropriate decimal code on the numeric keypad. For example, holding
:: [Alt] and pressing numeric keypad [1] and [0], and then releasing [Alt] will
:: result in a LineFeed.
::
:: The only way to enter a Null is by holding [Ctrl] and pressing the normal [2]
::
:: An alternate way to enter control characters 0x01 through 0x1A is by holding
:: the [Ctrl] key and pressing any one of the letter keys [A] through [Z].
:: However, [Ctrl-A], [Ctrl-F], [Ctrl-M], and [Ctrl-V] will be blocked on Win 10
:: if the console has Ctrl key shortcuts enabled.
::
:: This function works properly regardless whether delayed expansion is enabled
:: or disabled.
::
:: :getKey version 1.3 was written by Dave Benham, and originally posted at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=7396
::
:: This work was inspired by posts from carlos and others at
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=6382
::
:getkey
set "%1="
setlocal disableDelayedExpansion
for /f skip^=1^ delims^=^ eol^= %%A in (
  'replace.exe ? . /u /w'
) do for /f delims^=^ eol^= %%B in ("%%A") do (
  endlocal
  if "%%B" equ "" (set "%1=^!") else set "%1=%%B"
)
setlocal enableDelayedExpansion
if "!%2!" neq "" (
  if not defined %1 if "!%2:~0,1!" equ "0" (endlocal&endlocal&goto :getKey) else exit /b
  set "getKey.key=!%1!"
  set "mask=!%2:~1!"
  if not defined mask endlocal&endlocal&goto :getKey
  if "!getKey.key!" equ "=" (
    set "test=a!mask!"
    for /f "delims=" %%A in ("!test!") do if /i "!test:%%A=%%A!" equ "!test!" endlocal&endlocal&goto :getKey
  )
  for /f delims^=^ eol^= %%A in ("!getKey.key!") do if "!mask:*%%A=!" equ "!mask!" endlocal&endlocal&goto :getKey
)
exit /b