I need to know how can I check in batch file if the second batch file which is opened in other command window has stopped (waiting for argument or process not successful).
#echo off
:loop
start /wait rapidminer-batch.bat -f C:\Users\AHM-PC\Documents\ccc.rmp
echo cmd stopped
pause
goto loop
When called batch ends, it returns a value to errorlevel. It works for call, don't know if for start too.
if %errorlevel% gtr 0 (
echo failed
) else (
echo success)
or call exit /b <number of error> in your called batch, to return specific value. Check exit for more details.
The normal method to provide interbatch communication is a flag file
Either you create a flag file in the main routine and wait for the started routine to delete it or wait until the started batch creates a file, and delete it.
eg
echo.>myflag.txt
start anotherbatch.bat
:loop
timeout /t 1 >nul
if exist myflag.txt goto loop
Here, the batch will wait until myflag.txt is deleted, which you do in the second batch. All you need is for the two routines to agree on a filename to use.
Related
This question already has answers here:
Start multiple tasks in parallel and wait for them in windows?
(2 answers)
Closed 2 years ago.
I have a batch scripts that starts multiple processes (partly other batch files) in background via
start /b /min command1.exe some params
start /b /min command2.bat some params
start /b /min command3.exe some params
at the end of the top level batch script I would like to wait until all processes are completed.
Is there any way to achieve this without implementing special means within the called programs?
You can create special batch file that runs another process, waits for it to finish and creates a special file. Then launch desired processes with this script without wait and loop until all files are created.
Sample code for inspiration:
Runner.bat:
:: Run, wait and create file; %1 = file name, %2..N - process and params
set FileName=%1
shift
start /b /min /wait %* && (echo OK > %FileName%) || (echo Fail > %FileName%)
Main.bat:
call Runner.bat No1 command1.exe some params
call Runner.bat No2 command2.bat some params
...
:Check
... if not exist "No1", "No2", ... (
timeout /t 5
goto :Check
)
One option is to try to start them with WMIC process call create "c:\some.exe","c:\exec_dir" and assign the created PID to variable and checking periodically that the PIDs are existing.
You can try also with :
(
start "" /b command1
start "" /b command2
)|findstr "^"
echo all processes in the brackets block have ended
but if some of the commands is bat file you explicitly'll have to use exit 0 without /b switch.
My click.bat file:
:main
#start /wait cmd.exe -/c ""C:\Users\MY_USER_NAME\Desktop\2.bat" "
goto :main
My 2.bat file:
#echo off
echo Hello World!
#pause
I am clicking Click.bat and they are both opening (no problem in here).
After that I am closing the Hello World! prompt (2.bat).
and prompt of the Click.bat, ask me ^CTerminate batch job (Y/N)?
I want to auto answer at here (as N).
(When the answer is N, 2.bat opening again like as I want).
I agree with Mofi that addressing the real issue is always better than to work around it, but sometimes this isn't possible or you need a quicker solution.
Instead of passively waiting, until the second process finishes, just actively watch it. If it isn't alive anymore, restart it. That way, it doesn't matter, how the second process finishes/exits/crashes:
test1.bat
#echo off
:main
if exist MyCommand.flag goto :eof
start test2.bat
:wait
timeout 1 >nul
tasklist /fi "Windowtitle eq MyCommand"|find "cmd.exe" >nul || #goto :main
goto :wait
test2.bat
#echo off
title MyCommand
echo Hello World!
#pause
break>MyCommand.flag
You don't have to start cmd /c, because start alone already starts a new cmd process. Give the process a unique title, so you can check, if it is still running.
|| works as "if previous command (find) fails then"
find is neccessary, because tasklist does not provide a helpful errorlevel.
Note: you also need a method to stop, when the second process finishes its task.
Test2.bat writes an empty file when finished. Obviously the file wouldn't be created, when the process crashes before (or is forcefully terminated).
test1.bat simply checks for the existence of the file before restarting the second process.
I am running 1 st batch utility calling another 2nd batch. The 2nd batch calls a setup.cmd command which has internal Java code to patch files.
When I just call the 2nd batch from 1st batch --
1st batch calls the second batch
2nd batch calls the setup.cmd
1st batch continues with further code without waiting for setup.cmd to complete.
I tried using start /wait to call the setup.cmd but that does not returns back the control to 1st batch. It keeps the session after installing.
1st batch calls 2nd batch by using CALL
2nd batch has following code to call setup.cmd
%windir%\system32\cmd /c start /WAIT Disk1\setup.cmd %parameter%
How can I get the control back to 1st batch once the setup.cmd completes?
If you just use this without the start command, and call batch2 then it will wait until it is finished.
call Disk1\setup.cmd %parameter%
Resolved this last week by using loops and by calling the setup.cmd...sorry for delay in this post.
#echo off
CALL \Installers\Disk1\setup.cmd -i silent -FILE=\Silent\Silent.txt
:LOOP
tasklist /FI "username eq SOMEUSER" 2>NUL | find /I /N "java">NUL
ECHO %ERRORLEVEL%
if "%ERRORLEVEL%"=="1" (
GOTO CONTINUE
) ELSE (
ECHO PATCH is still running, Sleeping for 5 Mins
SLEEP 300
GOTO LOOP
)
:CONTINUE
I need to check whether a file is created and locked or not, using a batch file,
if the file is locked the program should wait and check periodically whether the file is released from lock, and when it gets unlocked the program should exit.
I am very new to writing batch files (started today)
This is what I have tried:
#echo off
:loop
if (2<nul (>>test.txt echo off))(
goto END
)
else (goto MESSAGE)
:MESSAGE
echo trying to access file
goto loop
:END
pause
You were close :) But you cannot use IF to directly test whether a command succeeded or not. Use the || conditional operator instead.
Assuming you mean Windows, and not DOS:
#echo off
:loop
2>nul (
(call ) >>test.txt
) || (
echo Trying to access file
timeout /nobreak 1 >nul
goto loop
)
(call ) is simply a very efficient way to perform a no-op that always returns success.
The TIMEOUT introduces a 1 second delay to prevent the loop from hogging CPU resources.
See How to check in command-line if a given file or directory is locked (used by any process)? for more info on how the above works.
I'd like to do something like:
start program1 ^>output
start program2 ^>output
and order the output so that the output is ordered. I don't care which output is first (program1's or program2's), but I'd like it to be a complete dump of that program's output.
Ideally, I'd like to run multiple programs in parallel with output all going to the screen, but a file would be fine. I don't need to see it while it is running, just have it intelligible when it's finished.
EDIT:
If I follow the suggestion to output them to a file then merge them when it's done, I have the trouble of waiting 'til all the programs are done -- so, I need a waitUntilAllTheStartsAreFinished command.
start program1 ^>output1
start program2 ^>output2
#... as many as I need
waitUntilAllTheStartsAreFinished
TYPE output1
TYPE output2
delete output1
delete output2
You can use a loop and tasklist:
:wait
rem just wait a second before looking again
ping -n 2 ::1 >nul 2>nul
tasklist 2>&1 | findstr /b "program1.exe program2.exe ..." >nul 2>&1 && goto wait
It will only continue further until all of program1.exe program2.exe ... are terminated.
Joey's suggested method will work, but it can become problematic if your programs can be launched multiple times. It becomes difficult to tell which tasks are the onces you want to monitor.
Each program will have an exclusive lock on the temporary output file until the program finishes. Any attempt by another process to redirect to the same file will fail. This can be used to detect when the program finishes.
I used TIMEOUT to insert a delay in the polling. If you are on a system like XP that does not have TIMEOUT then you can use ping -n 2 ::1 >nul 2>nul instead.
I've included extensive documentation on how this solution works in the code. Edit - I have simplified the code a bit by removing one unneccessary code block level, and I improved the documentation.
#echo off
setlocal
REM Define a base name for the temporary output files. I've incorporated
REM a random number in the file name to generally make it safe to run this
REM master script multiple times simultaneously. It is unlikely a collision
REM will occur, but incorporating a timestamp in the name would make it more
REM reliable.
set "baseName=%temp%\output%random%_"
set /a "progCount=2, completedCount=0"
REM Start each program with both stdout and stderr redirected to a temporary
REM ouptut file. The program will have an exclusive lock on the output file
REM until it finishes executing. I've assumed the program is another batch file
REM and I use the START /B switch so that the programs are run in the same
REM window as this master script. Any console program will work, and the
REM /B switch is optional.
start /b "" ^"cmd /c test.bat ^>"%baseName%1" 2^>^&1^"
start /b "" ^"cmd /c test2.bat ^>"%baseName%2" 2^>^&1^"
REM etc.
REM Clear any existing completed flags, just in case
for /l %%N in (1 1 %progCount%) do set "completed%%N="
:loopUntilDone
REM Introduce a delay so we don't inundate the CPU while we poll
timeout /nobreak 1 >nul
REM Loop through each of the output file numbers.
REM Redirect the stderr for the DO block to nul so that if the inner
REM block redirection fails, the error message will be suppressed.
for /l %%N in (1 1 %progCount%) do (
REM Only test this particular program if the output file has been
REM created (in other words, the program has started) and we haven't
REM already detected that it has finished. Also redirect an unused
REM file handle to the output file in append mode. The redirection will
REM fail if the program has not completed. If the redirection fails then
REM the IF block is not executed.
if not defined completed%%N if exist "%baseName%%%N" (
REM We are within the block, meaning the redirection succeeded and
REM the program must have finished. So print out the results.
echo(
echo Ouput for program%%N
echo ---------------------------------------------
type "%baseName%%%N"
REM Set a flag so we know this program has finished
set completed%%N=1
REM Increment the completed count so we know when we are done
set /a completedCount+=1
) 9>>"%baseName%%%N"
) 2>nul
if %completedCount% neq %progCount% goto :loopUntilDone
del "%baseName%*"