Call Waiting Spinner Via Arguments In Batch Script - windows

I wanted to call waiting spinner on my batch script like this is my code:
#echo off
::-----------------------------Waiting-Spinner-------------------------------
:spinner
set mSpinner=%mSpinner%.
if %mSpinner%'==....' (set mSpinner=.)
cls
::----------------------------Subdomain-Script-------------------------------
echo Enumerating Subdomains From Script1 %mSpinner%
python2 enumsubdomain.py google.com > google.txt
SLEEP 1
goto spinner
echo Enumerating Subdomains From Script2 %mSpinner%
python2 enumsubdomain2.py yahoo.com > yahoo.txt
SLEEP 1
goto spinner
#pause
And this spinner text output should be something like this:
Enumerating Subdomains From Script1 ...<Here this dot will be animated]
Enumerating Subdomains From Script2 ...<Here this dot will be animated]
But it only outputs first line(Script1) and the 2nd script stops and doesn't outputs the 2nd line as well, i guess it's because of goto line in batch script and i have no idea what can be done here to make it work!

After clarification in your comment, you'd probably want something like this.
We start the commands in separate windows with new window titles per window, then we use tasklist to determine of either are still running. So both results will be echo if both run, or only one will be echod if only one runs.
#echo off
set done1=1
set done2=1
start "enum1" /min cmd.exe /C ^(python2 enumsubdomain.py google.com ^> google.txt^)
start "enum2" /min cmd.exe /C ^(python2 enumsubdomain2.py yahoo.com ^> yahoo.txt^)
:spinner
set mSpinner=%mSpinner%.
if "%mSpinner%"=="...." (set mSpinner=.)
cls
(tasklist /FI "WINDOWTITLE eq enum1" | findstr /i "cmd")>nul && echo Enumerating Subdomains From Script1 %mSpinner% || set done1=0
(tasklist /FI "WINDOWTITLE eq enum2" | findstr /i "cmd")>nul && echo Enumerating Subdomains From Script2 %mSpinner% || set done2=0
if %done1% equ 0 if %done2% equ 0 goto :eof
(sleep 1)>nul
goto :spinner

You want to use the spinner several times, so using a subroutine for the spinner is a good idea.
The main problem is: batch waits for a command to end before continuing with the next one, so you can't include the python command into the loop. Solution: start the command as an independent process and then start the "spinning loop". Break it, when the independent process does not exist anymore.
Here the subprocess :spinner takes a string as parameter (the message), making it flexible.
Instead of clearing the screen (cls) for each iteration of the loop, I took a different approach: overwriting the line over and over (less flickering and keeping the previous screen intact)
#echo off
setlocal EnableDelayedExpansion
REM create a CariageReturn:
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
cls
start /min "MySpinnerProcess" cmd /c "timeout 8 >google.txt"
call :spinner "Enumerating Subdomains From Script1"
start /min "MySpinnerProcess" cmd /c "timeout 5 >yahoo.txt"
call :spinner "Enumerating Subdomains From Script2"
echo finished.
goto :eof
:spinner
tasklist /fi "WindowTitle eq MySpinnerProcess" 2>nul | findstr /bilc:"cmd.exe" >nul || (
echo %~1 done.
goto :eof
)
set "mspinner=%mspinner%."
if %mspinner% == .... set "mspinner=."
<nul set /p ".=%~1 %mspinner% !CR!"
timeout 1 >nul
goto :spinner
For completeness my script for running the two scripts simultaneously. (very similar to Gerhard's solution, but keeping two spinners) (in my defense: I already had it ready when I asked you if you want them one after the other or simultaneously, but I just had to spend the sunny Sunday Afternoon outside)
#echo off
setlocal
::---------Waiting-Spinner---------
start /min "MyPhytonProcess1" cmd /c "timeout 8 >google.txt"
start /min "MyPhytonProcess2" cmd /c "timeout 5 >yahoo.txt"
:spinner
set mSpinner1=%mSpinner1%.
set mSpinner2=%mSpinner2%.
if %mSpinner1%==.... (set mSpinner1=.)
if %mSpinner2%==.... (set mSpinner2=.)
cls
::----------------------------Subdomain-Script-------------------------------
echo Enumerating Subdomains From Script1 %mSpinner1%
echo Enumerating Subdomains From Script2 %mSpinner2%
if "%mSpinner1%%mSpinner2%" == "Done.Done." goto :done
tasklist /FI "WindowTitle eq MyPhytonProcess1" 2>nul |find "cmd.exe" >nul || set "mSpinner1=Done"
tasklist /FI "WindowTitle eq MyPhytonProcess2" 2>nul |find "cmd.exe" >nul || set "mSpinner2=Done"
timeout 1 >nul
goto :spinner
:done
echo finished.
#pause

Related

Executing shell commands in parallel but limiting jobs (Windows without Cygwin)

Here is what I am trying to do. Suppose I have a program called myprogram.exe, which I have to execute 1000 times.
Under Windows, I could usually do something as simple as:
for /L %n in (1,1,1000) do start /myfolder/myprogram.exe
However, suppose I only have 5 CPU threads I can devote to running the 1000 instances of myprogram.exe, such that I launch only 5, then when one of these finishes another one is launched, etc until the whole 1000 end.
Under Linux and using GNU Parallel, I could simply do:
seq 1000 | parallel -N0 -j5 "nohup myprogram.exe"
How could I achieve something like that in Windows command line? Notice that in my case using Cygwin is not an option, so resorting to xargs and GNU Parallel under Windows are not options either.
Here is a way, by using powershell to do the process count. and using a simply set /a as counter.
#echo off
setlocal enabledelayedexpansion
set /a cnt=0
:counter
if !cnt! lss 1000 (
for /F "tokens=*" %%i in ('powershell ^(Get-Process -Name 'myprogram'^).count') do set proc=%%i
if !proc! lss 5 (
start "C:\myfolder\myprogram.exe"
set /a cnt+=1
)
goto :counter
)
You could add echo !cnt! in the line before goto :counter if you want to see it count.
It can be done without using delayedexpansion but I prefer to use it here.
This will run five processes in parallel. Each time one of them finishes, the next process will be started (so there are always 5 of them until they all are done)
#ECHO off
setlocal enabledelayedexpansion
set bunch=5
for /l %%a in (1,1,1000) do (
call :loop
echo processing: %%a
start "MyCommand" cmd /c timeout !random:~-1!
)
call :loop
goto :eof
:loop REM waits for available slot
for /f %%x in ('tasklist /fi "windowtitle eq MyCommand" ^| find /c "cmd.exe"') do set x=%%x
if %x% geq %bunch% goto :loop
goto :eof
Add the /min switch to start to minimize the started processes.
Give them a unique windowtitle (MyCommand here) to be able to count them.
Replace cmd /c timeout !random:~-1! with your actual command.
EDIT a slightly modified script, which may work better, if myprogram is a GUI (script above will work better with CLI applications):
#ECHO off
setlocal enabledelayedexpansion
set bunch=5
for /l %%a in (1,1,100) do (
call :loop
echo processing: %%a
start notepad.exe
)
call :loop
goto :eof
:loop REM waits for available slot
for /f %%x in ('tasklist /fi "imagename eq Notepad.exe"^|find /c "."') do set x=%%x
if %x% geq %bunch% goto :loop
goto :eof

Windows batch user input variable is not set within an if

I have a program which has following flow. Problem is the windows batch file doesn't properly checks errorlevel and doesn't set KILLSTS value. Could you please let me know what's wrong with this program and how to fix this?
Ask user to open an exe
if Yes
check exe is running or not
if running, ask user whether to close that exe
if yes close exe
run the exe
else
exit
Here is the sample batch file.
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P AREYOUSURE="Open Spring STS [y/n]>"
set AREYOUSURE=%AREYOUSURE:~0,1%
ECHO AREYOUSURE=%AREYOUSURE:~0,1%
IF /I %AREYOUSURE% == N (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" |find ":" > nul
ECHO Error %errorlevel%
IF %errorlevel% neq 0 (
SETLOCAL
SET /P KILLSTS="Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set KILLSTS=%KILLSTS:~0,1%
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
ENDLOCAL
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
I am getting below error
You need to learn how to properly format if statements.
You are formatting them as:
IF /I %KILLSTS% == Y TASKKILL /f /im "STS.exe"
When they should be formatted as:
if /i "%KILLSTS%"=="Y" (TASKKILL /f /im STS.exe)
The formatting doesn't really matter as such in simple batch files, but it's best to use the correct syntax which can handle special characters such as SPACES, AMPERSANDS, QUOTES, PIPE for when more complex variables are involved.
Updated script:
#ECHO OFF
#REM SETLOCAL ENABLEEXTENSIONS
SET /P "AREYOUSURE=Open Spring STS [y/n]>"
set "AREYOUSURE=%AREYOUSURE:~0,1% "
echo "AREYOUSURE=%AREYOUSURE:~0,1%"
IF /I "%AREYOUSURE%"=="N" (
SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
echo Existing Batch
EXIT /B %errno%
)
SETLOCAL
#REM SET KILLSTS=Y
tasklist /fi "IMAGENAME eq STS.exe" | find ":" > nul
ECHO Error %errorlevel%
IF "%errorlevel%" neq "0" (
call :escapeexpansion
)
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
exit /b
:escapeexpansion
SETLOCAL
SET /P "KILLSTS=Spring STS is running. Kill STS Process [y/n]>"
echo KILLSTS %KILLSTS%
set "KILLSTS=%KILLSTS:~0,1%"
echo KILLSTS AFTER SUBSTR %KILLSTS%
IF /I "%KILLSTS%"=="Y" TASKKILL /f /im "STS.exe"
ENDLOCAL
goto :EOF
The entire structure seems wrong to me; as well as pointlessly using SET /P instead of CHOICE.
#ECHO OFF
TASKLIST /FI "IMAGENAME eq STS.exe"|FIND ":">NUL 2>&1&&GOTO ASKIF
CHOICE /M "Spring STS is running. Kill STS Process"
IF ERRORLEVEL 2 GOTO ENDIT
TASKKILL /F /IM "STS.exe"
TIMEOUT 3 /NOBREAK>NUL
:ASKIF
CHOICE /M "Open Spring STS"
IF ERRORLEVEL 2 GOTO ENDIT
START "" "C:\sts-bundle\sts-3.8.3.RELEASE\STS.exe"
:ENDIT
Echo=Exiting Batch
TIMEOUT 3 /NOBREAK>NUL

Running two command prompt terminals in native windows, how can I redirect the output of one to the input of the other?

I have one Windows 10 command prompt running and awaiting input, and I wish to automate continuous and live input with a second command prompt. I have gotten the second command prompt to extract the desired variable, and I wish to send it to the other command prompt that is waiting for input.
The "awaiting input" command prompt must run in real time because it is connected to Plink (not an SSH session so no use of the -m command here) which is connecting to a microcontroller. So it cannot be accomplished (at least I don't think) with function calls.
I see that it can be done in UNIX environments: https://askubuntu.com/questions/496914/write-command-in-one-terminal-see-result-on-other-one
Thanks in advance and please advise,
--A hopeful beginner
Batch code starts 2 piped processes, one for getting keyboard input and writing to a file, and the other reading the data written. Note there isn't a cmd window for each process, but there are two new processes running. You may use cmd /c or start if you need two consoles.
Does it help?
#echo off
set "pipefile=pipefile.txt"
if "%~1" neq "" goto %1
copy nul "%pipefile%" >nul
"%~F0" getInput >>"%pipefile%" | "%~F0" readInput <"%pipefile%"
echo(
echo(Batch end...
ping localhost -n 1 >nul
del /F /Q "%pipefile%" 2>nul
exit/B
:getInput
set "input="
set/P "input="<CON
echo(%input%
if /I "%input%" equ "EXIT" exit
goto:getInput
:readInput
setlocal enableDelayedExpansion
set/P="enter some data [EXIT to exit] "
for /l %%. in () do (
set "input="
set/P "input="
if defined input (
if /I "!input!" equ "EXIT" exit
set/P="enter some data [EXIT to exit] "
)
ping 1.1.1.1 -w 10 -n 1 >nul 2>nul & rem avoid processor load (may be removed)
)
Running two console windows
#echo off
set "pipefile=pipefile.txt"
if "%~1" neq "" goto %1
del /F /Q "%pipefile%" 2>nul
copy nul "%pipefile%" >nul
start "writer" cmd /c ^""%~f0" readInput ^<"%pipefile%" ^"
start "reader" cmd /c ^""%~f0" getInput ^"
echo(
Echo batch end...
ping localhost -n 1 >nul
goto :EOF
:getInput
set "input="
set/P "input=enter some data [EXIT to exit] "
echo(%input%>>"%pipefile%"
if /I "%input%" equ "EXIT" exit
goto:getInput
:readInput
setlocal enableDelayedExpansion
for /l %%. in () do (
set "input="
set /p "input="
if defined input (
if /I "!input!" equ "EXIT" exit
echo(!input!
)
ping 1.1.1.1 -w 10 -n 1 >nul 2>nul & rem avoid processor load (may be removed)
)

Find opened process in Windows batch

I'm trying to write code which loops and tells if a certain process is opened or not. It should be a loop that will show me in real time if the process is opened or not. In other words, a text will change when the program is opened and change again when it's closed. Instead what I got was a flood with the same text and it doesn't show the 'echos' below it.
I tried this:
#echo off
goto xera
:start
tasklist /FI "IMAGENAME eq notepad.exe" | find /I "notepad.exe" > nul
IF %ERRORLEVEL% equ 0 ECHO is opened
IF %ERRORLEVEL% equ 1 ECHO isnt opened
:xera
set /p "=Status: " <nul &call :start //the code got 'stuck' here
ECHO Text 2 (doesnt show)
pause>nul
You are not terminating your sub-routine :start correctly. Try the following:
#echo off
goto xera
:start
tasklist /FI "IMAGENAME eq notepad.exe" | find /I "notepad.exe" > nul
IF %ERRORLEVEL% equ 0 ECHO is opened
IF %ERRORLEVEL% equ 1 ECHO isnt opened
exit /b
:xera
set /p "=Status: " <nul &call :start
ECHO Text 2 (doesnt show)
pause>nul
I inserted exit /b which tells the command interpreter to return to the command after the call statement that actually called it. You could also use goto :EOF instead. Type call /? for more information on how to call sub-routines in batch.

Batch file - how to kill process if there is only one instance of it running?

I'm trying to write a batch that checks how many instances of the process "example.exe" are running, and if there are two or more instances, leave it running. But if there is only one instance running, end the process. Here's what I have:
#echo off
wmic process where name="example.exe" | find "example" /c > %temp%\variable.txt
set /p value=<%temp%\variable.txt
if %value% lss 2 goto endprocess
if %value% gtr 1 goto continue
:endprocess
start taskkill /f /im example.exe
:continue
ECHO continue
#echo off
My issue is this: It always thinks value is lss 2 (it thinks there are less than 2 instances of the process running). However, in my task manager, I can see that there is obviously 2 instances running. I think it's an issue with defining the value maybe? I don't know, I'm quite new to this. Any help? Thanks!
UPDATE
Okay I've now changed it to this (suggested by Magoo)
#echo off
wmic process where name="example.exe" | find "example" /c > "%temp%\variable.txt"
set /p value=<"%temp%\variable.txt"
if %value% equ 1 goto endprocess
if %value% neq 1 goto continue
:endprocess
start taskkill /f /im example.exe
:continue
ECHO continue
#echo off
This still doesn't exactly work, but i changed the number of instances from 1 to 0 and it ended the process. In other words, 1 process was running, but this batch file thought that 0 were running. Any ideas now?
This uses tasklist in XP Pro and higher:
#echo off
tasklist /fi "imagename eq example.exe" /nh |find /i /c "example.exe" > "%temp%\variable.txt"
set /p value=<"%temp%\variable.txt"
if %value% equ 1 taskkill /f /im example.exe
ECHO continue
#echo off
You can do it with one line and no temp file also - this uses another findstr filter to check if the number is a single 1 on a line and then && is a conditional operator that will launch taskkill if it does find 1.
#echo off
tasklist /fi "imagename eq example.exe" /nh |find /i /c "example.exe"|findstr "^1$" >nul && taskkill /f /im example.exe
ECHO continue
#echo off
I'd suggest that you have a fault with your logic.
The code should go to endprocess if the number found is <2 - that is, 0 or 1. If the lss 2 test is failed, then the count must be 3+, so the gtr 1 test will always succeed.
I've no idea why you don't use simply
if %value% neq 1 goto continue
or even
if %value% equ 1 start taskkill /f /im example.exe
But probably you've not told us that you want to be able to detect other instance-counts - as well as concealing the name of the executable for which you are checking.
Now - it may have been really useful to show us the content of the file. Are you sure the file is actually being generated? What happens if you try using "%temp%\variable.txt" instead of %temp%\variable.txt - that is, "quote the filename" ?

Resources