Using Sleep with findstr in a .bat - sleep

I created a .bat file with the below lines
cd C:\MyFolder
d:
findstr "Apple" C:\log.txt |findstr "red" > red_apples.txt
SLEEP 3600
GOTO START
When the bat is executed, the SLEEP is not working and the commands are running continously.
Is there anything wrong with the code? Please help !

I don't believe Windows has a sleep, you can emulate it with ping, as shown in this example chkwait.cmd script:
#setlocal enableextensions enabledelayedexpansion
#echo off
echo %time%
call :waitfor 20
echo %time%
endlocal
goto :eof
:waitfor
setlocal
set /a "t = %1 + 1"
>nul ping 127.0.0.1 -n %t%
endlocal
goto :eof
The call :waitfor 20 in the above script will wait for twenty seconds:
pax> chkwait
10:18:13.42
10:18:33.51

SLEEP does not exist in windows batch script. You would have create your own Sleep wrapper EXE and call that from the batch. Or use the clever trick from #paxdiablo above.

Related

Call Waiting Spinner Via Arguments In Batch Script

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

In a CMD .BAT file, how to turn echo off locally?

In a CMD .BAT file, how to turn echo off locally i.e. such that upon exit, echo state is restored?
#ECHO Off
SETLOCAL
::call the sub
CALL q25232315s
:: just a command for something-to-do
DIR u:
GOTO :EOF
If this is the main routine, then if this is the called routine:
#SETLOCAL
#echo>u:\tempfile.txt
#FOR /f "tokens=3delims=. " %%a IN (u:\tempfile.txt) DO #SET state=%%a&#DEL u:\tempfile.txt
#ECHO OFF
:: just a command for something-to-do
DIR u:\destdir
ECHO %state%&EXIT /b
It would appear to restore the echo state to the caller whilst keeping mum about its own activities.

Closing a windows application after bat file runs

In my batch file I opened a file and printed its contents. Now I am trying to close the application. I used taskkill /f /im Ptedit50.exe from the cmd line and the program closes. I am having trouble getting it to work in the batch file. When I add that line after the print command they program exits and the print command never executes. If I insert the line at the end of the batch file the program does not exit. Where should I place the taskkill /f /im Ptedit50.exe line?
#echo off
setlocal
title My First batch file
echo Hello!
start Ptedit50.exe "c:\My Labels\PraxisBadge.lbx"
call :SendCtrlP "Name in Windowtitle"
exit /b
:SendCtrlP <app>
setlocal
set vbs=%Temp%\_.vbs
>%vbs% echo set s = CreateObject("Wscript.Shell")
>>%vbs% echo s.appactivate "%~1"
>>%vbs% echo s.sendkeys "^p"
>>%vbs% echo s.sendkeys "{ENTER}"
cscript //nologo %vbs%
if exist %vbs% del /f /q %vbs%
exit /b
taskkill /f /im Ptedit50.exe
exit /b
enter code here
Here is a Batch + JScript Hybrid example. I added a couple 2 second sleeps to allow the target program time to process the requests. Usually, applications launch a separate Print dialog, so I changed it to send the enter keypress to the Print dialog.
#if (#CodeSection == #Batch) #then
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: The first line in the script is...
:: in Batch, a valid IF command that does nothing.
:: in JScript, a conditional compilation IF statement that is false.
:: So the following section is omitted until the next "[at]end".
:: Note: the "[at]then" is required for Batch to prevent a syntax error.
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Batch Section
#echo off
:: Open Labels
start Ptedit50.exe "c:\My Labels\PraxisBadge.lbx"
:: Wait 2 Seconds
ping 192.0.2.2 -n 1 -w 2000 >nul
:: Send Ctrl+P and Enter
CScript //E:JScript //Nologo "%~f0" "Name in Windowtitle" "^p"
CScript //E:JScript //Nologo "%~f0" "Print" "~"
:: Wait 2 Seconds
ping 192.0.2.2 -n 1 -w 2000 >nul
:: Kill Program
taskkill /f /im Ptedit50.exe
exit /b 0
:: End of Batch
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#end
////////////////////////////////////////////////////////////////////////////////
// JScript Section
try
{
var WshShell = WScript.CreateObject('WScript.Shell');
var Title = WScript.Arguments.Item(0);
var Message = WScript.Arguments.Item(1);
WshShell.AppActivate(Title);
WshShell.SendKeys(Message);
WScript.Quit(0);
}
catch(e)
{
WScript.Echo(e);
WScript.Quit(1);
}
WScript.Quit(2);
What you want to achieve is from my perspective straight forward, so I would avoid usage of those setlocal, call and exit /b parts of your code as there is no real need in this code to jump there and back again rather than executing codes line by line.
I don't have your application to fully test it, but if I try it with notepad and text file following code is working for me:
#echo off
title My First batch file
echo Hello!
start notepad.exe test.txt
REM call :SendCtrlP "Name in Windowtitle"
:SendCtrlP <app>
REM setlocal
set vbs=%Temp%\my.vbs
>%vbs% echo set s = CreateObject("Wscript.Shell")
>>%vbs% echo s.appactivate "Name in Windowtitle"
>>%vbs% echo s.sendkeys "^p"
>>%vbs% echo s.sendkeys "{ENTER}"
cscript //nologo %vbs%
ping -n 5 localhost > NUL
if exist %vbs% del /f /q %vbs%
REM exit /b
taskkill /f /im notepad.exe
REM exit /b
echo enter code here
pause
I have REM'd your code intentionally for easier view what was removed.
This part is there in order to simulate wait/sleep on older or desktop OS systems.
ping -n 5 localhost > NUL
On server system this can be replaced by command sleep.
Seems that reason why it was not working for you is that you have actually killed your program before .vbs was able to print it out, therefore the sleep put in place and additionally as stated in the beginning usage of setlocal is not really necessary in such straight forward and simple batch files.
Hope this helps

Delay in a 'for' loop in a batch file

I have this code, and I want to make a delay in the for loop to measure one time and then make a delay and continue after that.
I tried:
timout / t 10/ nobreak
As it is shown in the code, but it didn't work.
: #echo off
set Looping_number=10 or anything else
FOR /L %%A IN (1,1,%Looping_number%) DO call :doit %%A
goto :eof
:doit
set pad=00%1
set num=%pad:~-2%
#set var1=var1.exe
#set var2=C:\...\...\... .txt
#set output=C:\....\output\%num%
Mkdir %output%
%var1% %var2% %Results%
timeout / t 10 / nobreak
goto :eof
But it says you can not delay?
How can I fix this problem?
You have extra spaces in your command:
timeout / t 10 / nobreak
You need to say:
timeout /t 10 /nobreak
You can try the ping method:
ping -n 10 localhost > nul

Determining if batch script has been started/executed from the command line (cmd) -or- To pause or not to pause?

I like to have a typical "usage:" line in my cmd.exe scripts — if a parameter is missing, user is given simple reminder of how the script is to be used.
The problem is that I can't safely predict whether potential user would use GUI or CLI. If somebody using GUI double-clicks this script in Explorer window, they won't have chance to read anything, unless I pause the window. If they use CLI, pause will bother them.
So I'm looking for a way to detect it.
#echo off
if _%1_==__ (
echo usage: %nx0: filename
rem now pause or not to pause?
)
Is there a nice solution on this?
You can check the value of %CMDCMDLINE% variable. It contains the command that was used to launch cmd.exe.
I prepared a test .bat file:
#Echo Off
echo %CMDCMDLINE%
pause
When run from inside of open cmd.exe window, the script prints "C:\Windows\system32\cmd.exe".
When run by double-clicking, it prints cmd /c ""C:\Users\mbu\Desktop\test.bat" "
So to check if your script was launched by double-clicking you need to check if %cmdcmdline% contains the path to your script. The final solution would look like this:
#echo off
set interactive=1
echo %cmdcmdline% | find /i "%~0" >nul
if not errorlevel 1 set interactive=0
rem now I can use %interactive% anywhere
if _%1_==__ (
echo usage: %~nx0 filename
if _%interactive%_==_0_ pause
)
Edit: implemented fixes for issues changes discussed in comments; edited example to demonstrate them
:: exit if not interactive
echo %CMDCMDLINE% | find /i "/c"
if not ERRORLEVEL 1 goto:eof
Here, I wrote something...
Usage.bat
#echo off
if arg%1==arg goto help
goto action
:action
echo do something...
goto end
:help
set help1=This is Help line 1.
set help2=This is Help line 2.
cmd.exe /k "echo %help1% &echo %help2%"
goto end
:end
It's not perfect, but it works! :D
-joedf
This is only using the internal command. so effectively....
EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%~f0=!" pause >nul
or
if not "!cmdcmdline!" == "!cmdcmdline:%~f0=!" pause >nul
DisableDelayedExpansion
if "%cmdcmdline%" neq "%cmdcmdline:%~f0=%" pause >nul
or
if not "%cmdcmdline%" == "%cmdcmdline:%~f0=%" pause >nul
Start your batch checking for %WINDIR% in %cmdcmdline% like this:
echo "%cmdcmdline%" | findstr /ic:"%windir%" >nul && (
echo Interactive run of: %0 is not allowed
pause
exit /B 1
)
Please use findstr
echo %cmdcmdline% | findstr /ic:"%~f0" >nul && ( pause >nul )
or
setlocal EnableDelayedExpansion
.
.
echo !cmdcmdline! | findstr /ic:"%~f0" >nul && ( pause >nul )
.
.
endlocal
This is always worked...
for internal command
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~0,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
or
setlocal EnableDelayedExpansion
set "cmddiff=!cmdcmdline:~28,1!" & if !cmddiff! neq ^" ( pause >nul )
endlocal
You can compare the different thing, but this is only worked within EnableDelayedExpansion. and I don't think that this will be always worked, cause windows version, etc...
Similar approach...
setlocal
set startedFromExplorer=
echo %cmdcmdline% | find /i "cmd.exe /c """"%~0""" >nul
if not errorlevel 1 set startedFromExplorer=1
...
if defined startedFromExplorer pause
goto :EOF
setlocal EnableDelayedExpansion
if "!cmdcmdline!" neq "!cmdcmdline:%comspec%=!" ( pause>nul )
Test is done in Windows 10. Using %windir%, it is a little dangerous or ambiguous. So %comspec% is super safe.

Resources