I have the following problem:
I have created a batch script which calls itself in there (for being able to write a log in parallel). In the script I start another process (like start startServer.bat) which starts up a java process and keeps opened up all the time.
In my original script I wait 30 seconds, check if the process is running and do an:
exit /B 0
Unfortunately that does not work, the window shows that the exit /B 0 is being evaluated, but the window still keeps open. When I close the window with the other process (meaning the "child" processes started up in my .bat) my script continues its run.
So:
scriptA.bat
-> in there I call: start startServer.bat
-> wait 30 seconds
-> check is server is started
-> exit /B 0
Process hangs up!
What's very odd, if I wrap another script around, like:
scriptB.bat
-> call scriptA.bat
-----> in there I call: start startServer.bat
-----> wait 30 seconds
-----> check if server is started
-----> exit /B 0
-> scriptA.bat continues without any hangup!
I also tried the same with exit 0 (without /B) also, same result! In the first case it hangs up, in the second case my window closes as expected...
Has anyone of you ever had such a problem before and knows what's wrong here?
Process hangs up!
There's a good explanation of all the options for exiting a batch script here:
http://www.robvanderwoude.com/exit.php
Specifically, from that page:
The DOS online help (HELP EXIT) doesn't make it clear that the /B parameter exits the current instance of script which is not necessarily the same as exiting the current script.
I.e. if the script is in a CALLed piece of code, the EXIT /B exits the CALL, not the script.
So you definitely don't want exit /b 0 in this case. If just exit 0 doesn't work, try GOTO:EOF.
The earlier answer from Vicky is very good. There is some additional undocumented (or, at least, unclear) behaviour going on here.
In your question, you have a somewhat more complicated situation, but let's say you are calling/starting a batch file from the original, using exit /b 0 in the called batch file, and expecting that the ERRORLEVEL is accessible in the original.
Original
#echo off
start "" /b /wait cmd /c "startServer.bat"
if ERRORLEVEL 1 echo Exit code is one & exit /b 1
if ERRORLEVEL 0 echo Exit code is zero & exit /b 0
Child batch file
#echo off
exit /b 0
To get this to work, the start command must be used with the certain options. Depending on the options, they may need to be in a specific order. (!)
According to the docs at SS64 on Start, you should be able to use the /b and /wait switches. The documentation does not state that the order of these switches matters, but it does.
For instance, this will NOT work (commands run out of order, and ERRORLEVEL is not returned):
start "" /wait /b cmd /c "startServer.bat"
But this does work exactly as expected:
start "" /b /wait cmd /c "startServer.bat"
The only difference is swapping the /b and /wait switches.
I discovered this by accident, using the following steps:
Checked all the documentation I could find on start and call and cmd
Banged my head on the wall for a few hours trying everything I could think of
Gave up, and came back 24 hours later
I did not try anything new, I just started over, and it worked the first time. Comparing to previous file versions showed me this (apparently) small difference. Turns out, there is no such thing as a "small" change!
I guess your problem lies within the start command. The following excerpt from the start /? help might point to the issue:
command/program
If it is an internal cmd command or a
batch file then the command processor
is run with the /K switch to cmd.exe.
This means that the window will remain
after the command has been run.
If it is not an internal cmd command
or batch file then it is a program and
will run as either a windowed
application or a console application.
As a solution you could try to modify the start command like this:
start "" cmd /c "startServer.bat"
Related
bat files from another Main.bat file
Files contain something like follows and i want both to launch in 15 seconds delayed and stay untill i close each one of them with a "Ctrl+C", can someone please help me with this Use Case please.
Main.bat
echo Task-1:
call C:\Users\user\bat\My_bat1.bat
echo Task-2:
call C:\Users\user\bat\My_bat2.bat
My_bat1.bat
start /wait cmd.exe /k "cd PATH && mvn -P dev"
My_bat2.bat
start /wait cmd.exe /k "cd PATH && mvn -Dspring.profiles.active=dev,swagger,no-liquibase -Dspring.cloud.config.profile=dev -DskipTests=true"
If you are just asking how to delay your batch files by 15 seconds you can do it like this:
choice /t 15 /D y /n
If not can you please clarify your question?
EDIT: Based on your update, you want to add pause to your first child bat file, then the code above before the call command in your parent bat file.
You should really edit your question to include the sequence of events you want from the comments because it causes a lot of confusion.
I'll try to piece together what you want:
Start job 1, creating a new window
Do not wait for job 1 to finish, instead wait 15 seconds
Start job 2, creating a new window
If you press Ctrl+C in either window it should stop the job and close the window
I assume that if one job is terminated before or after the other is started, the other still needs to start or continue to work.
First of all, the program that currently runs - in your case that seems to be maven - actually receives Ctrl+C and decides how it wants to act on it. I'm not sure if it does in the way you want it to.
Main.bat
echo Task-1:
"%comspec%" /c "C:\Users\user\bat\My_bat1.bat"
timeout 15 /nobreak
echo Task-2:
"%comspec%" /c "C:\Users\user\bat\My_bat2.bat"
I added a timeout command between the launches. It waits 15 seconds.
If you removed /nobreak it would also be possible to interrupt the wait with a keystroke launching task#2 early
I find that call sometimes introduces wierd errors in such cases so I prefer "%comspec%" /c. It does the same thing except it does not receive back environment variables set in child file which is fine in your scenario.
My_bat1.bat
start "" "%comspec%" /c "cd PATH & mvn -P dev & timeout -1 /nobreak"
I removed /wait which prevented the second mvn instance from starting until the first one is finished or terminated.
I replaced /k with /c and added timeout to pause execution in stead of /k.
The timeout -1 /nobreak statement causes command interpreter to wait indefinitely without a chance to stop it except for Ctrl+C.
You can remove /nobreak to allow it to be closed with any keystroke if mvn exited normally (if that ever happens)
"%comspec%" is the same as cmd.exe but is preferred if Microsoft ever decides to change command interpreter exe name. Empty "" before is required because start interprets first double-quoted string as a window name.
I assume there is a folder named PATH inside current folder because it is not a variable. Furthermore, variable %PATH% is reserved for executable/library search path list and must not be assigned some random value or used with cd command unless you really know what you are doing. See path /?.
I also used & instead of && to prevent window from closing if mvn crashes.
My_bat2.bat can be changed similarly.
I made a Main batch file with the lines below:
#echo off
color 1e
title ------ Just a Test ------
start "C:\Users\%USERNAME%\Desktop\Check.bat"
:START
echo Welcome to the Game!
...
And Check.bat contains:
#echo off
if not exist "C:\Users\%USERNAME%\Desktop\Batch_System\importantFile.dll" goto ERROR
if exist "C:\Users\%USERNAME%\Desktop\Batch_System\importantFile.dll" goto CONTINUE
:ERROR
cls
echo ERROR :
echo Important file not found. please reinstall the program
pause
exit /b
:CONTINUE
cls
exit /b
When I use the command start, it starts only a command prompt with the Check.bat directory and the main batch file continues executing the game. I want to force close the main batch file if importantFile.dll doesn't exist.
Okay, let me explain: When the main batch file is executed and runs the command start to start another batch file called Check.bat, the file Check.bat checks if the file importantFile.dll exists, and if not, Check.bat displays an error message.
Does anyone know how to write Check.bat in a manner that when the .dll file does not exist, force the main batch file to exit?
First, help on every command can be get by running in a command prompt window the command with /? as parameter. start /? outputs the help of command START. call /? outputs the help of command CALL usually used to run a batch file from within a batch file. Those two commands can be used to run a batch file as explained in detail in answer on How to call a batch file that is one level up from the current directory?
Second, the command line
start "C:\Users\%USERNAME%\Desktop\Check.bat"
starts a new command process in foreground with a console window with full qualified batch file name as window title displayed in title bar at top of the console window. That is obviously not wanted by you.
Third, the Wikipedia article Windows Environment Variables lists the predefined environment variables on Windows and their default values depending on version of Windows.
In general it is better to use "%USERPROFILE%\Desktop" instead of "C:\Users\%USERNAME%\Desktop".
There is no C:\Users on Windows prior Windows Vista and Windows Server 2008 by default at all.
The users profile directory can be on a different drive than drive C:.
It is also possible that just the current user's profile directory is not in C:\Users, for example on a Windows server on which many users can logon directly and for which the server administrator decided to have the users' profile directories on a different drive than system drive making backup and cleaning operations on server much easier and is also better for security.
Well, it is also possible to have the user's desktop folder not in the user's profile directory. But that is really, really uncommon.
Fourth, on shipping a set of batch files, it is recommended to use %~dp0 to call other batch files from within a batch file because of this string referencing drive and path of argument 0 expands to full path of currently executed batch file.
The batch file path referenced with %~dp0 always ends with a backslash. Therefore concatenate %~dp0 always without an additional backslash with another batch file name, folder or file name.
See also What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory?
Fifth, I suggest following for your two batch files:
Main.bat:
#echo off
color 1e
title ------ Just a Test ------
call "%~dp0Check.bat" || color && exit /B
echo Welcome to the Game!
Check.bat:
#echo off
cls
if exist "%~dp0Batch_System\importantFile.dll" exit /B 0
echo ERROR:
echo Important file not found. Please reinstall the program.
echo/
pause
exit /B 1
The batch file Check.bat is exited explicitly on important file existing with returning exit code 0 to the parent batch file Main.bat. For that reason Windows command processor continues execution of Main.bat on the command line below the command line calling the batch file Check.bat.
Otherwise Check.bat outputs an error message, waits for a pressed key by the user and exits explicitly with non zero exit code 1. The non zero exit code results in Main.bat in executing the next command after || which is COLOR to restore initial colors and next executing also EXIT with option /B to exit the execution of Main.bat.
See also:
Single line with multiple commands using Windows batch file
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?
Where does GOTO :EOF return to?
exit /B without an additionally specified exit code is like goto :EOF.
The CALL command line in Main.bat could be also written as:
call "%~dp0Check.bat" || ( color & exit /B )
And Main.bat could be also written as:
#echo off
color 1e
title ------ Just a Test ------
call "%~dp0Check.bat"
if errorlevel 1 (
color
goto :EOF
)
echo Welcome to the Game!
I do not recommend using in Main.bat just EXIT instead of exit /B or goto :EOF. Just EXIT would result in exiting the current command process independent on calling hierarchy and independent on how the command process was started: with option /K to keep it running to see error messages like on opening a command prompt window and next running a batch file from within command prompt window, or with /C to close the command process after application/command/script execution finished like on double clicking on a batch file.
It is advisable to test batch files by running them from within an opened command prompt window instead of double clicking on them to see error messages on syntax errors output by cmd.exe. For that reason usage of just EXIT is counter-productive for a batch file in development. Run cmd /? in a command prompt window for help on Windows command processor itself.
Last but not least see:
Microsoft's command-line reference
SS64.com - A-Z index of the Windows CMD command line
start is asynchronous by default. Use start /wait so that main.bat can test the exit code of check.bat. Make check.bat return an appropriate exit code.
For example...
main.bat
#echo off
start /b /wait check.bat
if not %errorlevel% == 0 exit /b
echo "Welcome to the game!"
...
check.bat
#echo off
if exist "importantfile.dll" exit 0
echo ERROR: Important file not found. Please reinstall the program.
pause
exit 1
notes
Added /b to start to avoid opening another window. Change that per your preference.
You could use call instead of start but call gives the called code access to the variables of main.bat so encapsulation is improved if you use start as you did.
The logic in check.bat is simplified above. Once you identify the success path early in the script and exit, the rest of the script can assume the fail path. This saves you a few if's and labels which you might find simplifies writing and reading of similar scripts. Beware of potentially confusing multiple exit points in longer scripts though!
When choosing exit codes, 0 is a common convention for success.
The above code is just one technique - there are several other options (such as checksomething && dosomethingifok). Some useful information on return codes, and checking them, can be found in http://steve-jansen.github.io/guides/windows-batch-scripting/part-3-return-codes.html
Thanks to the answer from Mofi. I've my example and exp. on this. To be short, it's about the setting of log date format. You may change the format of time , date and log. you may have the result.
why-batch-file-run-with-failure-in-windows-server
I want to make a batch file that runs a particular program and then the command window exits itself, I tried this cause i will make a shortcut of that batch file so the batch file is in root directory
#echo off
"program.exe" "mainframe.pkg"
exit
it works but the black windows doesn't disappear and causes a fuss in the program cause it has perimeters. Any way to remove the black ugly CMD window.
Use the start command.
#echo off
start "" "program.exe" "mainframe.pkg"
The first quoted string after the start command is a console window title (if you are starting a console program); it can be an empty string as in my example. After that, specify the program name and its parameters.
You do not need the exit command at the end of the script. (In fact, I recommend against it without the /b parameter, because if you run the script from a cmd.exe prompt, your cmd.exe window will close without warning.)
You need to add exit 0 to the end of your program like so:
#echo off
start "program.exe" "mainframe.pkg"
exit /B 0
This should work, but let me know!
#echo off
start /B "" "program.exe" "mainframe.pkg"
exit /B 0
Thanks. Thought I'd try writing a batch file to kill another open cmd session that is constantly open churning out lots of scrolling info.
I got a bit carried away and am now outta my league so to speak.
Basically I am trying to search for "£000.00" within a each emerging line of tet that appears in the other running open command window. The running command session is named in the window as C:\windows\system32\cmd.exe but is does have a valid .exe process name in task manager while running and open.
The batch file code below is as far as I've got.
The idea is that when the above string is found in the other process that process/program get closed down them re-launched.
This is as far as I've got.
#echo off
#echo off
title Shut down other process and relaunch
:loop
start /d "C:\Users\Desktop" ActiveDOSprogram.exe
:: #setlocal enabledelayedexpansion
:: #echo off
:: set stringfound=1
find /c "*£000.00*" C:\Windows\system32\cmd.exe && (echo found %date% %time%:~0,-3% >> "%USERPROFILE%\Desktop\Crash_Report.txt"
taskkill /IM ActiveDOSprogram.exe /F
timeout /t 20
start /d "C:\Users\Desktop" ActiveDOSprogram.exe
goto loop
So when I tried this without any variables and in a loop and I think i nearly blew my PC!
Reason I'm stuck is I'm really a novice at this (but trying) and I got as far as I think I need a variable in there somewhere, that only move's to the next line (taskkill+restart) when £000.00 is found in the other process.
Thanks
wingman
When I run command Start C:\temp\sub2.bat in a command prompt window, errorlevel set is 4 and this is correct because a file which is indicated in batch does not exist. But when I run through this below, errorlevel returns 0. I have no idea why the exit codes are different.
Can anyone give me an advice for the reason?
#echo off
Call :Sub1
GOTO :EOF
:Sub1
start C:\temp\sub2.bat
echo %errorLevel%
Read the answer on How to call a batch file that is one level up from the current directory? It explains the 4 methods which exist to run a batch file from within a batch file and what are the differences.
You use command start which results in starting a new command process running parallel to the command process already executing your batch file for execution of C:\temp\sub2.bat.
The current command process immediately continues the execution of posted batch file and evaluates the exit code of command start which is 0 on successfully starting the executable or batch file.
You should use the command call to run the batch file as subroutine in your batch file and which makes it possible to evaluate the exit code set by C:\temp\sub2.bat.
#echo off
call C:\temp\sub2.bat
if errorlevel 1 echo There was an error with exit code %ERRORLEVEL%.
It would be also possible to start the other batch file in a new command process and what on its termination for example with exit 4 in current batch file.
#echo off
start /wait C:\temp\sub2.bat
if errorlevel 1 echo There was an error with exit code %ERRORLEVEL%.
In general it is not advisable to use exit without option /B as this results always in exiting the command process independent on calling hierarchy which makes it also impossible to debug a batch file by running it from within a command prompt window.
In case of C:\temp\sub2.bat really contains exit ExitCode without option /B and for some unknown reason the batch file can't be edited, it is really necessary to start C:\temp\sub2.bat in a separate command process and wait for its termination with start /wait.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
exit /?
if /?
start /?
Read also the Microsoft support article Testing for a Specific Error Level in Batch Files.
See also the Stack Overflow questions:
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?