如何在批处理文件中退出 SET /p 命令

4

如何在一定时间后退出SET /p命令?例如,如果用户输入时间太长,我希望退出SET /p。

4个回答

6
这是一个纯批处理方案,避免了使用Batch-JScript混合脚本时在未聚焦原始窗口时导致的问题。
@echo off
setlocal EnableDelayedExpansion

rem Execute a SET /P command with time out
rem Antonio Perez Ayala

rem If this file is re-executed as pipe's right side, go to it
if "%~1" equ "TimeoutMonitor" goto %1

del InputLine.txt 2> NUL
(
   set /P "line=You have 10 seconds to complete this input: " > CON
   > InputLine.txt call set /P "=%%line%%" < NUL
) 2> NUL | "%~F0" TimeoutMonitor 10
set /P "line=" < InputLine.txt
del InputLine.txt
echo Line read: "!line!"
goto :EOF


:TimeoutMonitor

rem Get the PID of pipe's left side
tasklist /FI "IMAGENAME eq cmd.exe" /FO TABLE /NH > tasklist.txt
for /F "tokens=2" %%a in (tasklist.txt) do (
   set "leftSidePipePID=!lastButOnePID!"
   set "lastButOnePID=%%a"
)
del tasklist.txt

rem Wait for the input line, or until the number of seconds passed
for /L %%i in (1,1,%2) do (
   ping -n 2 localhost > NUL
   if exist InputLine.txt exit /B
)

rem Timed out: kill the SET /P process and create a standard input line
taskkill /PID %leftSidePipePID% /F > NUL
echo/
echo Timed Out> InputLine.txt

exit /B

这个程序有一个依赖项,即当前用户对当前目录具有RWXD权限。但不能保证这一点。 - Bill_Stewart
3
在你的脚本上执行sed 's/InputLine.txt/"%TMP%"\InputLine.txt/g',问题就解决了,假设用户对%TMP%有写入权限,否则请将%TMP%替换为任何您希望使用的路径,前提是您使用sed进行搜索/替换,您必须用'\\'转义\。另一个选项是在notepad.exe中打开文件并执行搜索和替换。搜索:InputLine.txt 替换:“<somePathTheUserCanWriteTo>”\InputLine.txt这些是环境问题,Aacini无法猜测,通常很容易解决;您必须承认,他完成了最困难的部分。 - thecarpy
这是一个较旧的帖子,但这个答案让我感到好奇,我想知道如果你在批处理文件中使用它,它是如何工作的 - 这样不会终止调用的批处理脚本吗?肯定有类似于Start Call "%~dp0TimoutMonitor" "needlessArg"的方法吧?对我来说,使用Start Call一直是最稳定的异步运行文件的方式,但是如果是通过这种方式调用,它如何返回输入的值呢?在一些有限的测试中,我没有看到set /p单独打开一个新的CMD实例以获取最新的PID - k1dfr0std
原谅我 - 我进行了一些测试 - 现在我可以看到是“pipe”打开了新的“CMD”实例 - 非常好。而且,通过将set /p> InputLine.txt放在括号()内的“命令块”(如果你愿意这样称呼它)导致整个块被管道传输到文件本身中,不管怎样...?并且将stdOut发送到CON - 即使对于set /P命令也是如此 - 这允许CON(sole)保持set /P的处理同时保持环境?请参阅https://ss64.com/nt/con.html - 希望我接近理解这个特性。非常非常酷。 - k1dfr0std
今晚最后一条评论 - 通过将其输出到“CON(sole)” - 将CON设备存储在管道输出中的新实例CMD中作为暂存区,管道的第二部分调用自身以进行计时器,杀死存储在_CON_中的管道实例的CMD并允许块外的行(set /P "line=" < InputLine.txt)...而且 - 由于第一个set /p被存储在CON中,这就是CMD解释器如何从起始批处理环境中返回第一个set /p的值,因为它是从内部调用的...更接近了吗?2> Nul用于消除管道中的错误。 - k1dfr0std

2
基本上,你是不能的。
你可以尝试使用choice来接受单个字符并设置等待超时时间。

0
下面是一个批处理-JScript混合脚本,可以实现你想要的功能。JScript已经随着Windows XP及以后的每个版本一同安装。请将此文件保存为.bat扩展名。
@if (@CodeSection == @Batch) @then


@echo off
rem Give the desired wait time in milliseconds:
start "" /B Cscript //nologo //E:JScript "%~F0" 10000
set "input=Time out"
set /P "input=You have 10 seconds to complete this input: "
echo Input read: %input%
goto :EOF


@end


WScript.Sleep(WScript.Arguments(0));
WScript.CreateObject("WScript.Shell").SendKeys("{ENTER}");

这个解决方案只有在发送Enter按键时,焦点在控制台窗口上时才“有效”。因此,这不是一个真正健壮的解决方案。 - Bill_Stewart
@Bill_Stewart 这可能是你能得到的最好的。 - John DOE
@JohnDOE - 在我看来,editv32/editv64是更好、更强大的解决方案。 - Bill_Stewart
如果允许下载工具,则Aacini的答案默认有效,这也是您可以获得的“最佳”结果。 - John DOE
@Bill_Stewart:你说得对。我在我的新答案中解决了这个问题。感谢您指出这个问题。;) - Aacini
显示剩余2条评论

0

如果允许使用可下载工具,则可以使用 editv64.exe(64 位)或 editv32.exe(32 位),并带上 -t 参数。例如:

editv64 -p "Enter something within 10 seconds: " -t 10 INP

这个工具还有其他的优点,比如在输入时隐藏输入字符串(-m),以及可以交互地编辑现有的环境变量。你可以在这里下载:

http://www.westmesatech.com/editv.html


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