I would like to force command line to wait for his own process, because this process app.exe must finish, and takes some time. I use artificial timeout to prevent script from closing, because if I set the timeout wrong, then app.exe gives wrong results. I have problem with correct estimate timeout.
I read something about options /w and /k but I don't know where it insert.
Maybe wait for process would be good solution, but I don't know how can I do it.
Code is below:
(
#echo instruction1 to app.exe
#echo instruction2 to app.exe
#echo instruction3 to app.exe
#echo instruction4 to app.exe
timeout 3
) | app.exe > out.txt
This script is called from another application written in c++ but not from app.exe. I have windows 7.
The line which run script:
system("script.bat");
you may use start command to make a batch script wait for itself
#echo off
if /I "%~1" EQU "runme" goto %~1
start "" /B /WAIT cmd /c "%~s0 runme %*"
exit /B
:runme
(
#echo instruction1 to app.exe
#echo instruction2 to app.exe
#echo instruction3 to app.exe
#echo instruction4 to app.exe
) | app.exe > out.txt
timeout 3
exit /B
EDIT: may I misunderstood your question, perhaps this is what you're asking for
start "" /B /WAIT cmd /c "app.exe some_parameter_here"
start "" /B /WAIT cmd /c "app.exe some_parameter_here"
start "" /B /WAIT cmd /c "app.exe some_parameter_here"
...
or
start "" /B /WAIT cmd /c "echo some_parameter_here | app.exe"
start "" /B /WAIT cmd /c "echo some_parameter_here | app.exe"
start "" /B /WAIT cmd /c "echo some_parameter_here | app.exe"
...
Related
I have Windows 10 and inside of my batch file I do the following:
start cmd /k "Build_x1.bat"
start cmd /k "Build_x2.bat"
start cmd /k "Build_x3.bat"
...
start cmd /k "Build_xN.bat"
The reason that I have it as start cmd is because I want it to open in a new window; they all finish at different times and in their own window, they output their own warnings and errors of files they are compiling. As they finish, they produce a .adb file to my directory. In this same script, I want to xcopy the *.adb into a different directory. The problem I am running into is that I don't know how to start the xcopy only after all of the above cmd's finish in their own window. So I want:
start cmd /k "Build_x1.bat"
start cmd /k "Build_x2.bat"
start cmd /k "Build_x3.bat"
...
start cmd /k "Build_xN.bat"
xcopy /s/y *.adb "C:\*some directory*"
but xcopy only after all of the above start cmd have finished. Any thoughts on how I could achieve this? I've tried a few methods but all have failed and prematurely try to copy files without them being ready.
Start them with a title and check for their windows. Loop until they all are finished:
start "MyTitle" cmd /c "Build_x1.bat"
start "MyTitle" cmd /c "Build_x2.bat"
start "MyTitle" cmd /c "Build_x3.bat"
...
start "MyTitle" cmd /c "Build_xN.bat"
:loop
timeout 1
tasklist /fi "WindowTitle eq MyTitle" |find "cmd.exe" && goto :loop
echo all of them are finished
PS: if those batch file names are like in your example, you can start them with:
for /l %%i in (1,1,%n%) do start "MyTitle" cmd /c "Build_x%%i.bat"
NOTE: cmd /k keeps the windows open, so you will have to manually close each of them.
Starting the commands like you do initiates them in a different window and you release control of it from the parent. So few options, You could initiate them all at once using start /b which will start them all separately, but in the same window, but log their stdout and stderr to file (one per batch file) then the copy can be initiated after the batch is completed:
#echo off
set "list=Build_x1.bat Build_x2.bat Build_x3.bat Build_xN.bat
for %%I in (%list%) do start "" /b "%%I">>"%%~nI.log" >2%1
xcopy /s/y *.adb "C:\*some directory*"
if you want to see the results of each files output at the end of the run:
#echo off
set "list=Build_x1.bat Build_x2.bat Build_x3.bat Build_xN.bat
for %%I in (%list%) do (
echo **** Log for %%~I *** >>"%%~nI.log"
start "" /b "%%I.bat">>"%%~nI.log" >2%1
)
xcopy /s/y *.adb "C:\*some directory*"
type Build Build*.log
or to see them all in independent windows:
#echo off
set "list=Build_x1.bat Build_x2.bat Build_x3.bat Build_xN.bat
for %%I in (%list%) do start "" /b "%%I.bat">>"%%~nI.log" >2%1
xcopy /s/y *.adb "C:\*some directory*"
for %%I in (%list%) do start "%%~nI" cmd /k type "%%~nI.log"
I am finding it difficult to modify the script here to suit my requirements:
https://stackoverflow.com/a/12665498/4683898
#echo off
setlocal
set "lock=%temp%\wait%random%.lock"
:: Launch one and two asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" cmd /c 9>"%lock%1" one.bat
start "" cmd /c 9>"%lock%2" two.bat
:Wait for both scripts to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
( rem
) 9>"%lock%%%N" || goto :Wait
) 2>nul
::delete the lock files
del "%lock%*"
:: Launch three and four asynchronously
start "" cmd /c three.bat
start "" cmd /c four.bat
I am using a batch script, not to execute further batch scripts, but simply executing cmd commands (which run for a period of time) in parallel, and that works fine with the above script.
However, I want to be able to run more than just 2 commands/scripts, i.e. 3, 4, 5, (or whatever I desire) commands at a single time, running in parallel, let's call it, x.
So, I want to run x amount of cmd commands (that are executing in parallel), wait for them to terminate (using /c), and then executing the next bunch of x amount of cmd commands, and then the next bunch, etc, etc, until all cmd commands have executed.
How could I modify that script accordingly? (I have made a few attempts albeit with repeating errors "The process cannot access the file because it is being used by another process." in the initiating batch script; I presume this 'file' refers to the lock file.)
Thanks
EDIT:
#echo off
setlocal
set "lock=%temp%\wait%random%.lock"
call :a start cmd.exe /c somecommandA 1
call :a start cmd.exe /c somecommandB 2
call :wait
call :a start cmd.exe /c somecommandC 1
call :a start cmd.exe /c somecommandD 2
call :a start cmd.exe /c somecommandE 3
exit /b
:a
start "%~2" cmd /c 9>"%lock%%2" %1
exit /b
:wait
1>nul 2>nul ping /n 2 ::1
for %%N in (%lock%*) do (
( rem
) 9>"%%N" || goto :Wait
) 2>nul
You can call the files easily with this script:
#echo off
setlocal
set "lock=%temp%\wait%random%.lock"
call :a one.bat 1
call :a two.bat 2
call :wait
call :a three.bat 1
call :a name.bat 2
call :a gfwagwa.bat 3
exit /b
:a
start "%~2" cmd /c 9>"%lock%%2" %1
exit /b
:wait
1>nul 2>nul ping /n 2 ::1
for %%N in (%lock%*) do (
( rem
) 9>"%%N" || goto :Wait
) 2>nul
call :wait simply replaces the waiting. Whenever you have called all files that are to be run asynchronously, call the wait function. Then you can call more scripts.
The second parameter is the number of the lock file. Make sure you don't have duplicate numbers before all those scripts using them are closed (i.e. before the next call :wait). Though you're not going to run out of numbers anyway, no reason to use duplicates.
just to offer an alternative way:
#ECHO off
start "MyCommand-%~n0" cmd.exe /c ping localhost
start "MyCommand-%~n0" cmd.exe /c ipconfig /all
start "MyCommand-%~n0" cmd.exe /c sysinfo
:loop
tasklist /fi "windowtitle eq MyCommand-%~n0" | find "===" >nul && goto :loop
echo finished!
Edit for your comment. bunch is the number of commands running in parallel.
#ECHO off
setlocal enabledelayedexpansion
set bunch=3
for /f "delims=:" %%a in ('findstr /n /b "REM ==" %~f0') do set /a datastart=%%a+1
set count=0
for /f "skip=%datastart% usebackq delims=" %%a in ("%~f0") do (
set /a "count=(count+1) %% %bunch%"
echo starting: %%a
start "MyCommand-%~n0" cmd.exe /c %%a
if !count!==0 echo waiting & call :loop
)
echo waiting & call :loop
echo finished!
goto :eof
:loop
tasklist /fi "windowtitle eq MyCommand-%~n0" | find "===" >nul && goto :loop
goto :eof
REM == START DATA ==
ping localhost
ipconfig /all
systeminfo
tasklist
echo hello
schtasks /query
wmic bios get /value
timeout 10
the first for just gets the line number where your commands are (start of DATA section)
I want to manage to execute and manipulate my bat file, but, în background i want a countdown so that after a specific time, no matter what, my bat calls another one that deletes it, or simply closes.
Also i want the bat file to show up on execution maximized. I have set /max after start command, but still minimized. I used în my bat /min and it worked, cant figure out why /max doesent work.
To make it start maximized put this at the top of your script, below #echo off
if not "%1" == "max" start /MAX cmd /c %0 max & exit/b
I'll update this answer later with the other part, but I think opening a new batch with a timeout as soon as this one starts with start /B should help a lot.
EDIT
So this starts your script with a second script in it. That second script kills the first script and starts a third cmd to delete itself:
#echo off
if not "%1" == "max" start /MAX cmd /c %0 max & exit/b
set T=%TEMP%\sthUnique.tmp
wmic process where (Name="WMIC.exe" AND CommandLine LIKE "%%%TIME%%%") get ParentProcessId /value | find "ParentProcessId" >%T%
set /P A=<%T%
SET PID=%A:~16%
echo #echo off > killParent.bat
:: replace the 5 on the next line with any other number
echo timeout /t 5 /nobreak >> killParent.bat
echo start "" cmd ^/c timeout ^/t 1^^^&del "%%~f0"^^^&exit ^/b >> killParent.bat
echo taskkill /f /PID %PID% >> killParent.bat
START /B CMD /C CALL killParent.bat >NUL 2>&1
::any logic here instead of pause
pause
Place your code where the pause is and replace the 5 with the number of seconds you want to wait.
This does have the drawback of not being able to finish before the timer runs out, you can fix that by putting echo title parentKiller >> killParent.bat below echo #echo off > killParent.bat and putting
del killParent.bat
taskkill /F /FI "WINDOWTITLE eq parentKiller *" /T
at the end of your execution path, so at the bottom of your batch file normally. This would then look like this:
#echo off
if not "%1" == "max" start /MAX cmd /c %0 max & exit/b
set T=%TEMP%\sthUnique.tmp
wmic process where (Name="WMIC.exe" AND CommandLine LIKE "%%%TIME%%%") get ParentProcessId /value | find "ParentProcessId" >%T%
set /P A=<%T%
SET PID=%A:~16%
echo #echo off > killParent.bat
echo title parentKiller >> killParent.bat
:: replace the 5 on the next line with any other number
echo timeout /t 5 /nobreak >> killParent.bat
echo start "" cmd ^/c timeout ^/t 1^^^&del "%%~f0"^^^&exit ^/b >> killParent.bat
echo taskkill /f /PID %PID% >> killParent.bat
START /B CMD /C CALL killParent.bat >NUL 2>&1
::any logic here instead of pause
pause
del killParent.bat
taskkill /F /FI "WINDOWTITLE eq parentKiller *" /T
I am running a command in command prompt and I want to kill it after 15 minutes. I don't care if it is completed or not. I don't want to have any human interaction to kill the running command such as someone has to press CTRL+C to kill it.
Is there a way to do it.
Please note I don;t want to use any third party tools or scripts.
start forfiles /s
timeout /t 5
Taskkill /im forfiles.exe /f
is one way.
Did you mean something like that ?
#echo off
Tracert www.google.com
timeout /t 900 /nobreak >NUL
Taskkill /im cmd.exe /f
Edit : based on the blueray's comment :
how can I put this command in a single line to use in CMD?
Tracert www.google.com & timeout /t 900 /nobreak >NUL & Taskkill /im cmd.exe /f
May be this could help
start your-command-here
ping 127.0.0.1 -n 120 > NUL
taskkill /im cmd.exe /f
Explanation:
start: this command starts executing your command
ping: it pings your local machine(ip : 127.0.0.1) for 120 sec and >NUL redirects the output to nowhere else the output of ping command will be displayed on the cmd screen
taskkill: it is used to kill any task
/im: image name of the process to be terminated. if the command is running on cmd then cmd.exe or any program that you need to kill.
Hope it helps.
Try this, works well for me:
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
#echo off
set _time=0
set _timeout=30
start myprocess.exe
:waitforprocess
set /A _time=_time+1
IF !_time! GTR !_timeout! goto TimedOut
rem TaskList will return the task list of the image as specific
rem or it will return INFO: No tasks are running.... so look for
rem the INFO statement using FindStr. FindStr will return a errorlevel
rem of 0 if it found the string and a 1 if it did not, so use that
rem to work out next steps.
rem -------------------------------------------------------------------
tasklist /NH /FI "IMAGENAME EQ myprocess.exe" | findstr INFO
rem ERRORLEVEL 1 = Did not find the string, so try again.
IF ERRORLEVEL 1 (
timeout /T 1 /NOBREAK > nul
goto :waitforprocess
)
GOTO DONE
:TimedOut
ECHO We timedout so will kill the process
taskkill /FI "IMAGENAME EQ myprocess.exe" /T /F
:Done
echo finished
In windows command prompt, when I want to run a program using input/output file, I always use batch command like the following: test.exe < input.in > output.out.
(test.exe is the name of program, input.it is the name of input file and output.out is the name of output file)
But if I use this command, I cannot set a time limit for that program (i.e. I cannot force the program to quit after an amount of time).
So what command I should use in order to do that? Thank you for helping me.
You can use taskkill command:
start test.exe
ping 127.0.0.1 -n 5
taskkill /im test.exe /f
Here it's killed after 5 seconds. You can specify any duration in seconds.
start "" /b cmd /c "test.exe <input.in >output.out"
timeout /t 10
tasklist | find "test.exe" >nul && taskkill /f /im test.exe
Start the program inside a cmd instance not attached to the current console, wait for 10 seconds and if program still in task list, kill it
EDIT - Updated to handle the case pointed in comments
#echo off
setlocal enableextensions
start "" /b cmd /c "test.exe <input.in >output.out"
call :timeoutProcess "test.exe" 10
if errorlevel 1 (
echo Program has been killed
) else (
echo Program has ended in time
)
exit /b
:timeoutProcess process timeout
for /l %%t in (1 1 %~2) do (
timeout.exe /t 1 >nul
tasklist | find "%~1" >nul || exit /b 0
)
taskkill /f /im "%~1" >nul
exit /b 1