为啥在“set /p”提示时使用 Ctrl+C 取消 Windows 批处理脚本会产生不一致的行为?
Posted
技术标签:
【中文标题】为啥在“set /p”提示时使用 Ctrl+C 取消 Windows 批处理脚本会产生不一致的行为?【英文标题】:Why does canceling a Windows batch script with Ctrl+C when prompted by "set /p" give inconsistent behavior?为什么在“set /p”提示时使用 Ctrl+C 取消 Windows 批处理脚本会产生不一致的行为? 【发布时间】:2022-01-18 04:35:54 【问题描述】:这是脚本 foo.cmd :
@echo off
echo hi
set /p foobar="???"
echo bye
当set /p
提示时,我按Ctrl+C
取消脚本。此时,发生了几种可能的事情之一,似乎是随机选择的:
-
出现
^C
,后面跟着Terminate batch job (Y/N)?
^C
出现,然后是The syntax of the command is incorrect.
然后脚本终止,没有回显bye
。
^C
出现,脚本继续,回显 bye
。
我也见过类似 1 或 2 的情况,但 ^C
出现在“终止”提示或语法错误消息之后。
连续三次尝试的实际输出:
C:\Users\Me\Documents>foo.cmd
hi
???^CThe syntax of the command is incorrect.
C:\Users\Me\Documents>foo.cmd
hi
???^Cbye
C:\Users\Me\Documents>foo.cmd
hi
???^CTerminate batch job (Y/N)? y
C:\Users\Me\Documents>
我发现了一个 7 年前的相关问题,但答案没有解释为什么会发生这种情况:set /p reads ctrl+c as input instead of terminating the script
【问题讨论】:
我在批处理文件运行时看到了这种行为的变化。显然 cmd.exe 正在逐行读取文件,并且在执行命令的过程中可能会被移动的行弄糊涂。 @kindall 感谢您的评论。就我而言,我没有在文件运行时对其进行任何更改。我唯一能想到的可能会无意中改变的是我按下和释放 Ctrl+C 的速度(但我没有注意到我的手指速度与我得到的结果之间有任何关联。) 实际上,我刚刚看到另一种情况,我看到^C
后跟bye
,只有然后我才收到Terminate batch job (Y/N)?
消息。更奇怪的是,我得到了一个插入符号^
,然后是bye
,然后是C
,然后是Terminate...
消息。
现在,我最好的猜测是有一个线程等待set /p
的输入,另一个线程检查 Ctrl+C 然后取消作业。也许当我按下 Ctrl+C 时,两个线程都会读取它,这会引发两者之间的竞争。但我真的只是在这里猜测。
【参考方案1】:
set /p
在cmd
内部是等待输入的命令之一。 CTRL+C
意味着停止进程正在内部杀死 set /p
进程。
正如另一个内部进程timeout
所证明的那样,结果是相似的,但有一个实例是^C
字符由换行符分隔。这个批处理文件只包含timeout /t 5
,然后我随机执行CTRL+C
:
为了证明CTRL+C
在您的示例中杀死了内部进程,然后是主进程,我们可以在脚本本身中创建CTRL+C
(所有功劳归用户DBenham
用于exit code
创建^C
:
@echo off
echo hi
set /p foobar="???" || cmd /c exit -1073741510
echo bye
运行此命令并在set /p
提示符下按Enter
将完成set
命令,在^C
之后直接发出。每次运行的结果都将保持不变,因为CTRL+C
只有主进程要关闭:
【讨论】:
以上是关于为啥在“set /p”提示时使用 Ctrl+C 取消 Windows 批处理脚本会产生不一致的行为?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在VC++6.0下用C语言调用引用参数如:void Creat(SqList &L)总是提示&出错?
登录失败,在 Azure DevOps 中使用 ctrl+c 取消对 Git 的基本凭据提示