为啥在“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 /pcmd 内部是等待输入的命令之一。 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 批处理脚本会产生不一致的行为?的主要内容,如果未能解决你的问题,请参考以下文章

kafka win10启动为啥提示 系统找不到指定的路径

为啥有这个提示“Escape character is ”

为啥在VC++6.0下用C语言调用引用参数如:void Creat(SqList &L)总是提示&出错?

登录失败,在 Azure DevOps 中使用 ctrl+c 取消对 Git 的基本凭据提示

为啥python运行json会提示JsonDecodeError?

为啥是 Ctrl+.当我将它绑定到 Emacs 中的命令时不起作用?