如何在Windows批处理文件中创建一个“您确定”的提示框?

127

我有一个批处理文件,可以自动将大量文件从一个地方复制到另一个地方,然后再复制回来。但问题是,尽管它帮了我很多忙,但我经常不小心从我的命令缓冲区中选择该命令,并且会导致还未提交的更改被覆盖。

我需要在我的.bat文件中添加什么代码,才能使其输出“你确定吗?”,并要求我在运行文件的其余部分之前输入 Y ?

如果键入除 Y 以外的任何内容,则应退出该行的执行。

当我调用exit时,它会关闭cmd.exe,这不是我想要的。

14个回答

215
你想要的是这样的东西:
@echo off
setlocal
:PROMPT
SET /P AREYOUSURE=Are you sure (Y/[N])?
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END

echo ... rest of file ...


:END
endlocal

7
我唯一会添加的是在提示符前面加上额外的SET AREYOUSURE=N,以便在该命令窗口中之前已运行过脚本的情况下清除选择。如果没有它,那么默认值将保留先前选择的选项。 - isapir
5
我很确定setlocalendlocal可以解决这个问题。 %AREYOUSURE%endlocal之后将不再存在。 - user837703
1
@dudeprgm 你可能是对的。我想我在我的代码中错过了那些部分。 - isapir
8
这句话的重点在于那两行,如果加上一些解释性的文字会更有价值。 - Wolf
应该将代码行 SET /P AREYOUSURE=Are you sure (Y/[N])? 替换为 SET /P AREYOUSURE=Are you sure Y/[N]?,去掉括号以避免影响代码。 - DefToneR
显示剩余2条评论

42

尝试使用CHOICE命令,例如:

CHOICE /C YNC /M "Press Y for Yes, N for No or C for Cancel."

11
“炫耀”:虽然这是比较新的东西,它在1993或1994年加入了MS-DOS 6,所以它可能不能与所有实现一起使用。 - Nathan Fellman
12
这是一个关于如何在计算机上使用“choice”命令的示例。请点击链接查看具体操作步骤:http://www.computerhope.com/issues/ch001674.htm - Matthew Lock
1
这个命令并没有真正解释接下来该怎么做。虽然它链接到一个网页,但是那个页面随时可能被删除。Mofi的回答更好。 - cantsay

28

在Windows命令行中,有两个可用于用户提示的命令:

  • set选项,适用于所有启用命令扩展的Windows NT版本
  • choice.exe默认适用于Windows Vista及更高版本的PC用户以及Windows Server 2003及更高版本的服务器版本。

set是Windows命令处理器cmd.exe的内部命令。提示用户输入字符串的/P选项仅在启用命令扩展时可用,默认情况下启用命令扩展,否则几乎没有批处理文件能够正常工作。

choice.exe是一个独立的控制台应用程序(外部命令),位于%SystemRoot%\System32中。Windows Server 2003的choice.exe文件可以复制到Windows XP机器上的%SystemRoot%\System32目录中,以便在Windows XP上使用,就像许多其他默认不可用于Windows XP但在Windows Server 2003上默认可用的命令一样。

出于以下原因,最好使用CHOICE而不是SET /P

  1. CHOICE 只接受在选项 /C 后指定的键(从 STDIN 读取的字符),如果用户按下错误的键,则输出错误提示音。
  2. CHOICE 不需要按除可接受键之外的任何其他键。一旦按下可接受的键,CHOICE 就会立即退出,而 SET /P 要求用户使用 RETURNENTER 完成输入。
  3. 使用 CHOICE 可以定义默认选项和超时时间,在几秒钟后自动继续使用默认选项而无需等待用户。
  4. 使用类似于 echo Y | call PromptExample.bat 的方式从另一个批处理文件自动回答提示时,CHOICE 的输出效果更好。
  5. 由于 CHOICE 根据按下的键(字符)退出并分配给 ERRORLEVEL,因此用户选择的评估要容易得多,可以轻松地进行下一步评估。
  6. 如果用户仅按下 RETURNENTER 键且在提示用户之前未定义,则在 SET /P 上使用的环境变量未定义。如果在定义之前定义了 SET /P 命令行上使用的环境变量并且用户仅按下 RETURNENTER 键,则该环境变量将保持其当前值。
  7. 用户可以在提示时输入任何内容,包括字符串,这些字符串后来会导致批处理文件执行退出,因为存在语法错误,或者在未编写良好的批处理文件中执行未包含的命令。需要一些努力才能使 SET /P 对错误的用户输入进行安全设置。
这是一个使用首选CHOICE和替代SET /P在运行Windows的计算机上不可用的choice.exe的提示示例。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
echo This is an example for prompting a user.
echo(
if exist "%SystemRoot%\System32\choice.exe" goto UseChoice

setlocal EnableExtensions EnableDelayedExpansion
:UseSetPrompt
set "UserChoice="
set /P "UserChoice=Are you sure [Y/N]? "
set "UserChoice=!UserChoice: =!"
if /I "!UserChoice!" == "N" endlocal & exit /B
if /I not "!UserChoice!" == "Y" goto UseSetPrompt
endlocal
goto Continue

:UseChoice
%SystemRoot%\System32\choice.exe /C YN /N /M "Are you sure [Y/N]?"
if not errorlevel 1 goto UseChoice
if errorlevel 2 exit /B

:Continue
echo So you are sure. Okay, let's go ...
rem More commands can be added here.
endlocal

注意:此批处理文件使用命令扩展,不支持在Windows 95/98/ME上使用command.com作为命令解释器,而应该使用cmd.exe

添加命令行set "UserChoice=!UserChoice: =!"是为了使其能够在Windows NT4/2000/XP上通过echo Y | call PromptExample.bat调用,而不需要使用echo Y| call PromptExample.bat。它会在运行两个字符串比较之前从STDIN读取的字符串中删除所有空格。

echo Y | call PromptExample.bat 的结果是将YSPACE分配给环境变量UserChoice。这会导致处理提示两次,因为"Y "既不是大小写不敏感等于"N",也不是等于"Y",需要先删除所有空格。因此,UserChoice的值为YSPACE,将导致在第二个提示执行中再次运行提示,并使用批处理文件中定义的默认选项N,从而导致意外退出批处理文件处理。是的,安全使用SET /P确实很棘手,不是吗?

choice.exe 在用户按下 Ctrl+CCtrl+Break 并在接下来回答由 cmd.exe 输出的问题以使用 N 终止批处理作业的情况下,将以退出代码 0 退出。因此,条件 if not errorlevel 1 goto UserChoice 被添加以再次提示用户使用 YN 的批处理文件代码中的提示来确定答案。感谢 dialer 提供关于这种可能的特殊用例的信息。

批处理标签 :UseSetPrompt 下方的第一行也可以写成:

set "UserChoice=N"

在这种情况下,用户选择输入是预定义的N,这意味着用户可以只按RETURNENTER(或Ctrl+CCtrl+Break和下一个N)来使用默认选择。

提示文本由批处理文件中的命令SET输出。因此,提示文本通常应以空格字符结尾。命令CHOICE从提示文本中删除所有尾随的普通空格和水平制表符,然后将自己的空格添加到提示文本中。因此,命令CHOICE的提示文本可以写成带有或不带有末尾空格。这在执行时对显示的提示文本没有影响。

用户提示评估的顺序也可以完全更改,如dialer所建议的那样。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
echo This is an example for prompting a user.
echo(
if exist "%SystemRoot%\System32\choice.exe" goto UseChoice

setlocal EnableExtensions EnableDelayedExpansion
:UseSetPrompt
set "UserChoice="
set /P "UserChoice=Are you sure [Y/N]? "
set "UserChoice=!UserChoice: =!"
if /I not "!UserChoice!" == "Y" endlocal & exit /B
endlocal
goto Continue

:UseChoice
%SystemRoot%\System32\choice.exe /C YN /N /M "Are you sure [Y/N]?"
if not errorlevel 2 if errorlevel 1 goto Continue
exit /B

:Continue
echo So you are sure. Okay, let's go ...
endlocal

如果用户按下了确定键Y,则此代码将导致在批处理标签:Continue下继续进行批处理文件处理。否则,执行N的代码,结果退出批处理文件处理并独立于用户是否真正按下该键、故意或错误地输入其他内容,或按下Ctrl+CCtrl+Break并决定接下来的提示输出由cmd不终止批处理作业。

有关使用SET /PCHOICE提示用户从选项列表中选择的详细信息,请参阅 如何在 Windows 命令解释程序上停止在不正确的用户输入时退出批处理文件执行?上的答案。

更多提示:

  1. IF 比较运算符左右两个字符串时,要包括双引号在内。因此,不是将 UserChoice 的值与 NY 进行大小写不敏感的比较,而是将 UserChoice 的值用双引号括起来,再与 "N""Y" 进行比较。
  2. IF 比较运算符 EQUNEQ 主要用于比较范围在 -2147483648 到 2147483647 之间的两个整数,而不是用于比较两个字符串。虽然 EQUNEQ 也可以用于字符串比较,但在尝试将左侧字符串转换为整数后,结果是对双引号中的字符串进行比较。只有启用命令扩展时,才能使用 EQUNEQ 运算符。用于字符串比较的运算符是 ==not ... ==,即使禁用了命令扩展,它们也能正常工作,因为 MS-DOS 和 Windows 95/98/ME 的 command.com 也支持这些运算符。有关 IF 比较运算符的更多详细信息,请参阅Windows 批处理文件中等效于 NEQ、LSS、GTR 等的符号
  3. 命令 goto :EOF 需要启用命令扩展才能真正退出批处理文件的处理过程。有关详细信息,请参阅GOTO :EOF 返回到哪里? 也可以使用 exit /B,即使禁用了命令扩展,它也能正常工作,但会输出一个禁用命令扩展的错误消息。在任何执行环境中,都可以使用 exit /B 2>nul 来退出批处理文件的处理过程,而不显示任何错误消息。在这两个批处理文件示例中,使用 exit /B 是因为它比 goto :EOF 更短。由于执行环境在批处理文件的前两行命令中已经完全定义,所以这两个命令在示例中都能正常工作。

为了理解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • choice /?
  • echo /?
  • endlocal /?
  • exit /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?

另请参见:


1
choice.exe 自 DOS 6.0 起就存在了。 - Brian Minton
1
@BrianMinton 这不对。在 MS-DOS 6.0、MS-DOS 7.0、Windows 95 和 Windows 98 中,默认情况下提供了可用的 16 位应用程序 CHOICE.COM。但是,在 Windows NT4、Windows 2000 和 Windows XP 中,默认情况下没有安装 choice.exeCHOICE.COM 也可以在 NT4、Windows 2000 和 Windows XP 上使用,但最好使用适当的资源工具包中的 32 位 choice.exe。请参阅 Rob van der Woude 的页面关于 CHOICECHOICE.COMchoice.exe 之间的选项部分不同。然而,问题不是关于 DOS。 - Mofi
1
这里有一个是/否的情况(其中“否”被伪装成“不取消”)。不要使用if Cancel do CancelAction else do YesAction,而是使用if Yes do YesAction else do CancelAction或者if not Yes do CancelAction else do YesAction。重点是不要在if语句中检查Cancel条件,而是使用Yes条件。这也适用于CHOICECHOICE 可以返回0或255(既不是1也不是2),此时程序的行为不正确。 - dialer

17

choice命令并非在所有地方都可用。对于较新的Windows版本,set命令具有/p选项,您可以使用该选项获取用户输入。

SET /P variable=[promptString]

查看 set /? 以获取更多信息。


12

这里稍微简单一些:

@echo off
set /p var=Are You Sure?[Y/N]: 
if %var%== Y goto ...
if not %var%== Y exit
或者
@echo off
echo Are You Sure?[Y/N]
choice /c YN
if %errorlevel%==1 goto yes
if %errorlevel%==2 goto no
:yes
echo yes
goto :EOF
:no
echo no

在 Y 后放置您想要发生的命令。这就是 ... 的作用 :) - Bob Smith
我的意思是:%errorlevel% 始终是一个整数值。请参阅此处的文档,其中包括一个示例。 - Stephan
终于有人理解这个问题了。 - Mike Q

3
这是我用来获取“是/否”回答的方法。

它不区分大小写。

这只是检查输入中给出的错误,并将choice变量设置为您需要的任何值,以便在下面的代码中使用。

@echo off
choice /M "[Opt 1]  Do you want to continue [Yes/No]"
if errorlevel 255 (
  echo Error
  ) else if errorlevel 2 (
  set "YourChoice=will not"
  ) else if errorlevel 1 (
  set "YourChoice=will"
  ) else if errorlevel 0 (
  goto :EOF
  )
  echo %YourChoice%
  pause

2

您还可以使用“Choice”命令

@echo off
echo Sure?

CHOICE /C YN 

IF %ERRORLEVEL% EQU 1 goto CONTINUE
IF %ERRORLEVEL% EQU 2 goto END

:END
exit

:CONTINUE
echo hi
pause

2

有很多答案,但似乎没有一个简单明了的。这是我正在使用的代码:

choice /M "Do you want to continue?"

if %errorlevel% EQU 1 (
    ... run your code lines here
)

0

我会以以下方式进行,以确保在循环等过程中测试和变量是正确的。

:: rem at the top of the script
setlocal enabledelayedexpansion

:: choice example
CHOICE /C YNC /M "Continue? Press Y for Yes, N for No or C for Cancel."
If /I "[!errorlevel!]" NEQ "[1]" ( GOTO START_OVER )

0
这是一个简单的示例,我在 Windows 10 上的备份 (.bat / batch) 脚本中使用它,可以让我在进行备份时拥有不同的选项。
...

:choice
set /P c=Do you want to rsync the archives to someHost[Y/N]?
if /I "%c%" EQU "Y" goto :syncthefiles
if /I "%c%" EQU "N" goto :doonotsyncthefiles
goto :choice

:syncthefiles
echo rsync files to somewhere ...
bash -c "rsync -vaz /mnt/d/Archive/Backup/ user@host:/home/user/Backup/blabla/"
echo done

:doonotsyncthefiles
echo Backup Complete!

...

您可以拥有任意数量的这些块。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接