Прежде чем ответить на ваш вопрос, я должен указать, что цикл 1000 раз не обязательно означает, что вы приостановили на 1 секунду. Есть лучшие способы спать - timeout /t seconds
в Vista или новее, или ping -n seconds+1 localhost
или choice /t seconds
в XP. Вы также должны избегать топания на existing environment variables, например %time%
.
Чтобы ответить на ваш вопрос, нет изящного способа установить тайм-аут для set /p
. Тем не менее, вы можете запустить фоновый поток в том же окне, используя start /b
, чтобы повторять события на интервале. Вы можете настроить межпоточную связь между активным потоком и фоном, используя waitfor
(только для Vista или новее), чтобы сбросить таймер и установить вспомогательный поток для самоуничтожения, когда waiter.txt исчезает.
И до тех пор, пока вы запускаете одну вспомогательную нить в том же окне, также можете добавить туда свою цепочку waiter.txt. Зачем создавать минимальное окно, когда вы можете повторно использовать тот, который у вас уже есть? И так как мы объединяем потоки процессов в одном окне, вы также можете сделать еще один шаг и объединить все свои сценарии в один скрипт, который снова запускается с разными аргументами для разных потоков.
@echo off
setlocal
if "%~1"=="" (
>waiter.txt echo 0
start /b "" "%~f0" helper1
start /b "" "%~f0" helper2
) else goto %~1
:begin
cls
set /p "seconds="<waiter.txt
echo Alive for %seconds%s.
:read-host
set "cho="
set /p "cho="
if not defined cho goto read-host
rem // delayed expansion prevents evaluation of special characters in user input
setlocal enabledelayedexpansion
for %%c in (quit exit die EOL) do if /i "!cho!"=="%%c" (
del waiter.txt
echo OK, bye!
)
rem // send signal to helper2 acknowledging entry
waitfor /s %computername% /si UserEntry >NUL 2>NUL
if not exist waiter.txt exit /b
rem // ========================================
rem // Do something meaningful with !cho! here.
rem // ========================================
endlocal
goto begin
rem // formerly b1.bat
:helper1
set "num=0"
:helper1_loop
timeout /t 1 /nobreak >NUL 2>NUL
set /a num+=1
if not exist waiter.txt exit
>waiter.txt echo %num%
goto helper1_loop
:helper2
if not exist waiter.txt exit
waitfor /t 60 UserEntry >NUL 2>NUL || (
echo A minute has passed without input.
)
goto helper2
Для дополнительного кредита, давайте избавимся от waiter.txt, а также. Я не уверен, основана ли эта паранойя или нет, но я считаю, что секторы жесткого диска могут выдержать конечное количество записей. Перезаписывать waiter.txt один раз в секунду для потенциально часов беспокоит меня. Итак, давайте создадим гибридный кусок Jscript для вычисления секунд, прошедших между началом скрипта и теперь.
Для управления выполнением вспомогательного потока фона мы по-прежнему будем использовать временный файл, но мы будем использовать lock file, который будет написан только один раз, а затем удален в конце.
@if (@CodeSection == @Batch) @then
@echo off
setlocal
if "%~1"=="" (
rem // relaunch self as helper if lock file is writeable
2>NUL (>"%~dpn0.lock" type NUL) && start /b "" "%~f0" helper
rem // create a lock file for the duration of the main runtime
rem // Credit: Dave Benham -- https://stackoverflow.com/a/27756667/1683264
8>&2 2>NUL (2>&8 9>"%~dpn0.lock" call :init) || (
echo Only one instance is allowed.
timeout /t 3 /nobreak >NUL
exit /b
)
) else goto %~1
rem // cleanup and end main runtime
del "%~dpn0.lock" >NUL 2>NUL
waitfor /s %computername% /si UserEntry >NUL 2>NUL
exit /b
:init
rem // set %start% to current epoch
call :jscript start
:begin
cls
call :jscript seconds
echo Alive for %seconds%s.
:read-host
set "cho="
set /p "cho="
if not defined cho goto read-host
rem // delayed expansion prevents evaluation of special characters in user input
setlocal enabledelayedexpansion
for %%c in (quit exit die EOL) do if /i "!cho!"=="%%c" (
echo OK, bye!
exit /b
)
rem // send signal to helper2 acknowledging entry
waitfor /s %computername% /si UserEntry >NUL 2>NUL
rem // ========================================
rem // Do something meaningful with !cho! here.
rem // ========================================
endlocal
goto begin
:helper
del "%~dpn0.lock" >NUL 2>NUL
if not exist "%~dpn0.lock" exit
waitfor /t 60 UserEntry >NUL 2>NUL || (
echo A minute has passed without input.
)
goto helper
:jscript
for /f %%I in ('cscript /nologo /e:JScript "%~f0" "%start%"') do set "%~1=%%I"
goto :EOF
@end // end batch/begin JScript hybrid code
WSH.Echo(
WSH.Arguments(0)
? Math.round((new Date() - WSH.Arguments(0))/1000)
: new Date().getTime()
);