问题
I want to create a batch file that both executes a command once, and do a loop at the same time. When the loop occurs again, the command won't be executed anymore. Here is the code for the loop:
@echo off
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
FOR /L %%n in (1,1,10) DO (
call :spinner
ping localhost -n 2 > nul
)
exit /b
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Rebuilding, please wait... !spinChars:~%spinner%,1!!CR!"
exit /b
However there's a problem: The loop will execute and only executes when the command is done. And there are no timeouts for the loop, so basically, it will do the loop forever, until I press Ctrl + C. Can anyone help me with this? And if you can, please make the code above better. Thanks in advance.
回答1:
Set a variable with a true value when the command is executed in the first instance, and Conditional testing in that variable prior to executing said command
If not "!EXC!" == "" (Echo First Run) Else (Set "EXC=True")
Example uses delayed expansion as it is usable both in For Loops and Label Loops.
If you want to Break the Loop, Use the conditional testing to Goto :Label
Update
Now that you've provided more detail in your question, I believe something like this is what you're going for.
@echo off
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~dpf0" ^> nul') do set "CR=%%a"
set "spinChars=\|/-"
for /f "delims=#" %%a in ('"prompt #$H# &echo on &for %%b in (1) do rem"') do (
set "BS=%%a"
set "BS=!BS:~0,1!"
)
<nul set/p=Rebuilding, please wait...
FOR /L %%. in () DO (
REM insert conditional testing to break loop Here
set /a "spinner=(spinner + 1) %% 4"
For %%/ in (!Spinner!) Do <nul set /p=%BS%!spinChars:~%%/,1!
)
exit /b
:End_Loop
Echo You have Exited the process
Pause
Exit /B
The Definition of the Backspace Character comes from this post
Whatever process your waiting for in the loading loop you will need some method to test for it's completion. Seeing as you've not detailed, I'll suggest some options:
- Existance of a file
- Value of a Variable
- result of testing against tasklist to see if a task is still active.
If you provide more detail regarding the command / process you are waiting on, a better answer regarding the conditional testing can be offered.
An example method that runs a subroutine as a seperate instance in the same window, and uses Signal Files to communicate to the main Loop when command execution has completed:
::: ** Batch Multithreading example by T3RRY ** :::
@Echo Off & CD "%~dp0" :::
:::::::::::::::::::::::::::::::::::::::::::::::::::
::: - Define any Variables to be used by both Environments
Set "spinChars=\|/-"
::: - Test if Thread Two is to be executed
If /I "%~1" == "Thread2" Goto :Thread2
::: - Localise Thread Ones Environment
Setlocal EnableDelayedExpansion
::: - Ensure previous Signal files removed in case program exited incorrectly
Del /Q /F "%TEMP%\CMDrun.log"
Del /Q /F "%TEMP%\CMDend.log"
CLS
::: - Define Backspace Character for Animation
For /F "delims=#" %%a in ('"prompt #$H# &echo on &for %%b in (1) do rem"') do (
Set "BS=%%a"
Set "BS=!BS:~0,1!"
)
<Nul Set/P=Processing, please wait.
:Loop
::: - Launch Thread Two in Same window if Not already Running
::: - Conditional tests on signal files redirect errors to Standard error to prevent erroneous output
::: - when testing occurs at the same time the file is being written to.
(IF Not Exist "%TEMP%\CMDrun.log" Start /B "" "%~F0" Thread2) 2>Nul
::: - Animation To indicate commands in thread one are running. A Loop is used in this example.
Set /A "spinner=(spinner + 1) %% 4"
For %%S in (!Spinner!) Do <Nul Set /P=%BS%!spinChars:~%%S,1!
::: - Exit Thread One once Thread Two has Completed
(IF Exist "%TEMP%\CMDend.log" Goto :End_Loop) 2>Nul
Goto :Loop
:End_Loop
::: - Clean up Signal Files
Echo.
Del /Q /F "%TEMP%\CMDrun.log"
Del /Q /F "%TEMP%\CMDend.log"
Echo Process Complete
Pause
::: - Demonstrate stability of multithreading through repetition
Start "" "%~F0"
Exit
:Thread2
::: Localise Thread Two's Environment
Setlocal EnableDelayedExpansion
>"%TEMP%\CMDrun.log" (Echo running)
::: - Title update to demonstrate commands executed in thread two are running
For /L %%# In (1,1,10000) Do (
Set /a "spinner=(spinner + 1) %% 4"
For %%S in (!Spinner!) Do TITLE !spinChars:~%%S,1! Output %%#
)
>"%TEMP%\CMDend.log" (Echo finished)
::: - Hard exit of Thread Two used to prevent script overflow.
EXIT
来源:https://stackoverflow.com/questions/61696996/executing-commands-one-with-a-loop-with-cmd