CMD .bat file include by "sub.bat" vs "CALL sub.bat" [duplicate] - windows

I'm using a batch file in folder1/folder2/file.bat
There is a batch file in parent folder folder1, that I want to open through file.bat
I have tried using:
start ..\..\code.bat
But this results in an error message, because file couldn't be found.
Any ideas?

I want to explain better what should be used with an example as the answers posted up to now work only with current working directory being the directory containing the batch file file.bat.
There is a directory structure as follows:
C:\
Temp
Folder 1
Folder 2
Example.bat
Parent.bat
The current working directory is C:\Temp on executing Example.bat either with
"Folder 1\Folder 2\Example.bat"
or with
"C:\Temp\Folder 1\Folder 2\Example.bat"
The batch file Parent.bat contains for example:
echo %0 is active.
pause
The batch file Example.bat contains already:
#echo off
echo Calling Parent.bat ...
rem How to run Parent.bat here?
echo %0 is active.
pause
The really working solutions in this scenario with the current working directory being a different directory than directory containing Example.bat are as follows.
Continue batch processing with Parent.bat
"%~dp0..\Parent.bat"
%0 references argument 0 on execution of the batch file which is always the name of the batch file as specified in parent process on starting the batch file.
But wanted is the drive and path of the batch file without double quotes. Therefore the expression %~dp0 is used to get C:\Temp\Folder 1\Folder 2\ from argument 0.
On this path the string ..\Parent.bat is appended, and additionally the entire new file name
C:\Temp\Folder 1\Folder 2\..\Parent.bat is enclosed in double quotes because of the spaces.
There is no return to Example.bat after processing of Parent.bat finished.
Call Parent.bat like a subroutine
call "%~dp0..\Parent.bat"
Command call results in execution of batch file Parent.bat in same command process (console window) with halting the execution of Example.bat until Parent.bat finished.
The batch execution continues on next line in Example.bat after processing of Parent.bat finished.
Exception:
Parent.bat contains command exit without switch /B because this results in an immediate exit of command line interpreter cmd.exe processing Example.bat and Parent.bat.
Execute call /? or help call in a command prompt window for short help on command call.
Start Parent.bat as parallel process
start "Parent Batch" "%~dp0..\Parent.bat"
Command start without any parameter with the exception of the optional title results in execution of batch file Parent.bat by a separate command process in a separate console window without halting the execution of Example.bat.
Therefore both batch files run at same time (more or less).
Note:
Command start interprets first string in double quotes as title. Therefore it is necessary to define explicitly a title in double quotes when the batch file or application to start, or any argument of the started batch file / application must be specified in double quotes because of 1 or more spaces.
Execute start /? or help start in a command prompt window for short help on command start.
Call Parent.bat as separate process
start "Parent Batch" /wait "%~dp0..\Parent.bat"
Command start with optional parameter /wait results in execution of the started batch file / application as separate process (additional console window for a batch file or console application), but halting the execution of the current batch file until the started process (Windows application or batch file / console application executed in a new console window) terminates itself.

..\ is used to go one level up. your case requires two levels up
Try:
start ..\..\code.bat

You could just:
cd..
start Code.bat
And that would start code.bat from its own directory

try to use this:
start ../code.bat

Related

Can I call %COMSPEC% without terminating all Windows batch execution?

Came across this oddity of batch behaviour as part of the build process in our systems that I'm trying to automate in Jenkins pipelines.
To skip to the meat of the problem and why I'm encountering it, the batch file I'm calling is a build generated batch file that must be called prior to another executable within the same command window to set up paths and alike for our executable to build our system. When building as a user this is fine, you just open the cmd console, run the batch, then run the executable. However in Jenkins I have to pass all commands effectively as one batch file to make it call within the same window, unless I want to mess around with configuring all those paths by hand using withEnv or something.
Something along the lines of this in my Jenkins groovy script:
// Option 1 - && operator
bat "env_configuration.bat && env_dependent_exec.exe"
// Option 2 - multi line version
bat """env_configuration.bat
env_dependent_exec.exe
"""
// Option 3 - same using calls, yadda yadda
bat """call env_configuration.bat
call env_dependent_exec.exe
"""
// Option 4 - Place these calls in batch file and call that instead
bat "run_it_all.bat"
As part of the batch file however, for whatever reason, it has this command within it.
%COMSPEC%
exit /b 0
This will call "C:\WINDOWS\system32\cmd.exe" and output the Mircrosoft version and related blurb.e.g:
Microsoft Windows [Version 10.0.19045.2486]
(c) Microsoft Corporation. All rights reserved.
The catch is, calling this executable will immediately end all batch execution. The line "exit /b 0" isn't actually hit, something whoever created this process I assume never realised. After this batch file process completes, all subsequent commands/calls, (Option 1 above is the easiest to repro) are never hit as all batch processing just stops. This is visible directly in cmd itself, you don't need Jenkins to reproduce.
I will probably wind up just find and replacing this line to comment it out or something... but I refuse to believe I can't find some way of stopping %COMSPEC% from ending all execution of whatever batch file calls it. If I were to guess, I would guess that cmd.exe calls EXIT as it finishes and kills all....
For the sake of interest I have tried modifying the batch file in numerous ways to try and see if I can call %COMSPEC% and still get the rest of the batch script to run afterwards.
:: This fails the same way
call %COMSPEC%
exit /b 0
:: This succeeds to run, but spawns another cmd window that doens't print in the original calling batch file output, so doesn't achieve the original goal
start %COMSPEC%
exit /b 0
:: call %COMSPEC% via subroutine also immediately terminates, we never see "echo 2"
call :comspec_call
exit /b 0
:comspec_call
#echo %COMSPEC% echo 1
%COMSPEC%
#echo %COMSPEC% echo 2
I would guess cmd.exe calls the EXIT command flat on termination, hence the process death, but I've yet to find a means to prevent it doing so...
I've checked %COMSPEC% for flags that might just printout and terminate nicely, but any flags I've found that do provide this information, also terminate with EXIT (I think)
Does anyone has any idea how to call this line and continue execution as I assume the original dev intended?
Cheers in advance!
Batch processing doesn’t just stop — you have started another command interpreter, and the one that launched it is waiting for the new instance to terminate. As it doesn’t quit, everything appears to halt and you wind up killing both to get things back to normal.
Create a new batch script that does everything:
:: controller.bat
#echo off
call env_configuration.bat
call some_other.bat
env_dependent_exec.exe
...
Use of the call command causes the command shell to invoke a script using the current interpreter.
Now your Jenkins groovy script should be:
bat controller.bat
(Disclaimer: I don’t know Jenkins, so...)
Thanks to #Duthomhas and #Magoo
The problem here is that a call to %COMSPEC% launches a new command line process that must terminate before the rest of the script can continue. I didn't understand that cmd.exe was spawning a new script that the call script was waiting to terminate.
With a simplified recap:
:: env_configuration.bat
#echo env_configuration before COMSPEC
#%COMSPEC%
#echo env_configuration after COMSPEC
:: controller.bat
#echo controller before env_configuration.bat
#call env_configuration.bat
#echo controller after env_configuration.bat
controller.bat && #echo back in shell
When you run controller.bat the process will output the Microsoft blurb, but halt.
If you enter "exit" at this point it will kick out of the terminal launched with %COMSPEC% and then all following script steps continue.
It appears the original dev needed the user to be in a new subprocess to continue. The final solution to doing as was intended here is:
:: env_configuration.bat
#echo env_configuration before COMSPEC
#call %COMSPEC% /C <whatever_command_or_exec_next>
#echo env_configuration after COMSPEC
:: controller.bat
#echo controller before env_configuration.bat
#call env_configuration.bat
#echo controller after env_configuration.bat
controller.bat && #echo back in shell
Cheers!

How to run a java process in the background and exit from script

I am trying to convert a bash script to batch, but I am having a trouble for this one issue. The script runs a java server in the background, waits for 5 seconds, then exit with exitcode. But in batch, I am unable...
runserver.sh
java -jar java_server.jar &
pid=$!
sleep 5
kill -0 $pid
cmdStatus=$?
if [ $cmdStatus -ne 0 ]
then
exit 1
fi
exit 0
runserver.bat
#echo off
set EXITCODE=0
start /b java -jar java_server.jar
timeout /t 5
for /f "tokens=1 delims= " %%i in ('jps -m ^| findstr java_server') do set PID=%%i
IF "%PID" == "" (
set EXITCODE=1
)
EXIT EXITCODE
but if I run the above batchscript, I am never able to disown the java process and it never exists
The first mistake in batch file code is missing % in line IF "%PID" == "" to really compare the value of the environment variable PID enclosed in double quotes with the string "". So correct would be IF "%PID%" == "". For more details on string comparisons see Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.
The second mistake is not using two times % on last command line EXIT EXITCODE around the environment variable EXITCODE to reference its value which would be correct written as EXIT %EXITCODE%.
But the batch file should be better written as follows:
#echo off
cd /D "%~dp0"
start "" /B javaw.exe -jar "%~dp0java_server.jar"
%SystemRoot%\System32\timeout.exe /T 5 /NOBREAK >nul
jps -m 2>nul | %SystemRoot%\System32\findstr.exe /L "java_server" >nul
The batch file first makes the directory of the batch file the current directory because of java_server.jar is most likely in directory of the batch file. %~dp0 expands to drive and path of argument 0 which is the batch file. The file path referenced with %~dp0 always ends with a backslash which is the directory separator on Windows which should be taken into account on concatenating this string with a file or folder name. The command CD fails only if the batch file is stored on a network resource accessed with a UNC path because of Windows prevents by default that a directory referenced with a UNC path instead of a drive letter becomes the current directory for downwards compatibility reasons because of many console applications work not correct with current directory not being on a drive with a drive letter.
The command START interprets first double quoted string as title for the console window opened on running a Windows console application in a separate command process. In this case no console window is opened because of using option /B although java.exe is a Windows console application. For that reason explicitly specifying an empty string with "" as window title like on starting a Windows GUI application is advisable to avoid that any other double quoted argument string is interpreted as optional window title.
The option /B is interpreted as background. Most people think that the started application is detached from current command process. This is true for Windows GUI applications, but not for console applications like java.exe. The handle STDIN of current command process is bind with STDIN of started console application. Also the output to the handles STDOUT and STDERR of started application are redirected to console window of the running command process which nevertheless continues immediately with execution of batch script. The option /B means just running the console application parallel to current command process without opening a new console window, but not in running the application completely detached from running command process.
The solution is quite simple in this case because there is also javaw.exe, the Windows version of Java designed for running a Java application completely in background detached from the process starting it.
A batch file for general usage works best on specifying all files with full qualified file name which means with full path, file name and file extension. Java executable can be installed everywhere and so the folder path for this executable can't be specified in the batch file. Windows command processor has to find the executable javaw in current directory or in any folder in list of folders of local environment variable PATH. But it is at least possible to specify the executable javaw with its file extension .exe as this file extension is well known.
The JAR file java_server.jar is specified with full path on assuming that this file is stored in same directory as the batch file. The batch file directory should be already the current directory and so %~dp0 would not be needed at all, but it does not matter to specify the file for safety with full path.
Next the standard Windows console application TIMEOUT is called with full qualified file name with options to wait 5 seconds unbreakable (requires Windows 7 or newer) and redirecting its output to device NUL.
I don't know anything about the file jps and have not even installed Java. For that reason I assume jps is an executable or script of which file extension listed in local environment variable PATHEXT and stored in directory of the batch file or any other directory of which path is listed in local environment variable PATH. It would be of course better to specify this file with file extension and if possible also with full path.
The standard output of jps is redirected to standard input of Windows standard console application FINDSTR and the error output to device NUL to suppress it.
FINDSTR runs a case-sensitive, literal string search for java_server on standard output of jps. The output of FINDSTR is of no interest and therefore redirected also to device NUL to suppress it.
FINDSTR exits with 0 on searched string really found and with 1 on nothing found. The batch file should exit with 1 on not successfully starting Java server and with 0 on Java server running. This matches exactly with exit code of FINDSTR and so nothing else must be done.
cmd.exe exits the execution of a batch file always with last exit code set by an application or command during batch file execution. This can be verified on commenting out second command line with rem and save it, running this batch file from within a command prompt window and running next in command prompt window if errorlevel 1 echo Java server not running! resulting in expected output Java server not running!. Then rem needs to be removed from second command line of batch file before saving the batch file which is run once again from within the command prompt window. After second batch file execution finished, running once again if errorlevel 1 echo Java server not running! results in no output while running if errorlevel 0 echo Java server is running. results in output Java server is running. as expected.
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 /? ... explains %~dp0
cd /?
echo /?
findstr /?
if /?
start /?
See also:
Microsoft article about Using command redirection operators
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?

startup batch file hangs up on second command

I created a startup bat file that looks like this
taskkill /im RemoteDesktopManager.exe
C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
"C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
"C:\Program Files\Mozilla Firefox\firefox.exe"
it does the first and second, but won't go any further, they all exist
how can I fix this?
update : I tried suggestion provided by #phd443322 and wrote this:
taskkill /im RemoteDesktopManager.exe
start "" /w C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
start "" /w "C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
start "" /w "C:\Program Files\Mozilla Firefox\firefox.exe"
intrestingly each command still waits for that program to be closed to continue to the next.
so why still not working?
Below there is a working Batch file, as first advised by phd443322:
taskkill /im RemoteDesktopManager.exe
start "" C:\Users\kheradmand\AppData\Local\Google\Chrome\Application\chrome.exe
start "" "C:\Program Files (x86)\JetBrains\PhpStorm 7.1.2\bin\PhpStorm.exe"
start "" "C:\Program Files\Mozilla Firefox\firefox.exe"
Batch files wait for programs to exit unlike interactive. These are the rules documented in the Start command.
If Command Extensions are enabled, external command invocation
through the command line or the START command changes as follows:
non-executable files may be invoked through their file association just
by typing the name of the file as a command. (e.g. WORD.DOC would
launch the application associated with the .DOC file extension).
See the ASSOC and FTYPE commands for how to create these
associations from within a command script.
When executing an application that is a 32-bit GUI application, CMD.EXE
does not wait for the application to terminate before returning to
the command prompt. This new behavior does NOT occur if executing
within a command script.
When executing a command line whose first token is the string "CMD "
without an extension or path qualifier, then "CMD" is replaced with
the value of the COMSPEC variable. This prevents picking up CMD.EXE
from the current directory.
When executing a command line whose first token does NOT contain an
extension, then CMD.EXE uses the value of the PATHEXT
environment variable to determine which extensions to look for
and in what order. The default value for the PATHEXT variable
is:
.COM;.EXE;.BAT;.CMD
Notice the syntax is the same as the PATH variable, with
semicolons separating the different elements.
When searching for an executable, if there is no match on any extension,
then looks to see if the name matches a directory name. If it does, the
START command launches the Explorer on that path. If done from the
command line, it is the equivalent to doing a CD /D to that path.

Restore default working dir if bat file is terminated abruptly

I have a scenario where during execution of a batch file, it navigates to a different folder (say to "../asdf"); and at the end of execution it will set the current working dir as the same folder from where the user called the .bat file.
But if the user terminates the batch processing before it is complete, the cmd show the current working dir (say "../asdf").
But in my case, I need to restore the working dir to the default/predefined one. Is it possible?
Batch file is written by me, so I can modify it.
CMD is opened through a desktop shortcut to CMD, which I have control of; so properties like working dir or passing args to CMD etc can be done there.
In your batch script use setlocal to encapsulate the running environment of your batch session. If the user terminates the script before you cd or popd to return, your script will still exit in the directory in which it started. Here's a brief test:
#echo off
setlocal
pushd c:\Users
cd
exit /b
Output:
C:\Users\me\Desktop>test.bat
c:\Users
C:\Users\me\Desktop>
Notice I didn't popd or cd %userprofile%\Desktop, but I still ended up back at my Desktop after the script exited.
Additionally, setlocal keeps you from junking up your environment with orphaned variables that mean nothing outside of your batch script. It's just good practice. At the console, type help setlocal for more info.

Pausing a batch file when double-clicked but not when run from a console window?

Is there a way for a batch file (in this case, running on Windows XP) to determine whether it was launched from a command line (i.e. inside a console window) or launched via the shell (e.g. by double-clicking)?
I have a script which I'd like to have pause at certain points when run via the shell, but not when run at a command line. I've seen a similar question on SO, but am unable to use the same solution for two reasons: first, whether or not it pauses needs to be dependent on multiple factors, only one of which is whether it was double-clicked. Second, I'll be distributing this script to others on my team and I can't realistically ask all of them to make registry changes which will affect all scripts.
Is this possible?
Found one :-) – After desperately thinking of what cmd might do when run interactively but not when launching a batch file directly ... I finally found one.
The pseudo-variable %cmdcmdline% contains the command line that was used to launch cmd. In case cmd was started normally this contains something akin to the following:
"C:\Windows\System32\cmd.exe"
However, when launching a batch file it looks like this:
cmd /c ""C:\Users\Me\test.cmd" "
Small demo:
#echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1
if defined DOUBLECLICKED pause
This way of checking might not be the most robust, though, but /c should only be present as an argument if a batch file was launched directly.
Tested here on Windows 7 x64. It may or may not work, break, do something weird, eat children (might be a good thing) or bite you in the nose.
A consolidated answer, derived from much of the information found on this page (and some other stack overflow pages with similar questions). This one does not rely on detecting /c, but actually checks for the name of the script in the command line. As a result this solution will not pause if you double-clicked on another batch and then called this one; you had to double-click on this particular batch file.
:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
The variable "testl" gets the full line of the cmd processor call, stripping out all of the pesky double quotes.
The variable "testr" takes "testl" and further strips outs the name of the current batch file name if present (which it will be if the batch file was invoked with a double-click).
The if statement sees if "testl" and "testr" are different. If yes, batch was double-clicked, so pause; if no, batch was typed in on command line (or called from another batch file), go on.
Edit: The same can be done in a single line:
echo %cmdcmdline% | findstr /i /c:"%~nx0" && set standalone=1
In plain English, this
pipes the value of %cmdcmdline% to findstr, which then searches for the current script name
%0 contains the current script name, of course only if shift has not been called beforehand
%~nx0 extracts file name and extension from %0
>NUL 2>&1 mutes findstr by redirecting any output to NUL
findstr sets a non-zero errorlevel if it can't find the substring in question
&& only executes if the preceding command returned without error
as a consequence, standalone will not be defined if the script was started from the command line
Later in the script we can do:
if defined standalone pause
One approach might be to create an autoexec.nt file in the root of c:\ that looks something like:
#set nested=%nested%Z
In your batch file, check if %nested% is "Z" - if it is "Z" then you've been double-clicked, so pause. If it's not "Z" - its going to be "ZZ" or "ZZZ" etc as CMD inherits the environment block of the parent process.
-Oisin
A little more information...
I start with a batch-file (test.cmd) that contains:
#echo %cmdcmdline%
If I double-click the "test.cmd" batch-file from within Windows Explorer, the display of echo %cmdcmdline% is:
cmd /c ""D:\Path\test.cmd" "
When executing the "test.cmd" batch-file from within a Command Prompt window, the display of
echo %cmdcmdline% depends on how the command window was started...
If I start "cmd.exe" by clicking the "Start-Orb" and "Command Prompt" or if I click "Start-Orb" and execute "cmd.exe" from the search/run box. Then I execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\system32\cmd.exe"
Also, for me, if I click "Command Prompt" from the desktop shortcut, then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is also:
"C:\Windows\system32\cmd.exe"
But, if I "Right-Click" inside a Windows Explorer window and select "Open Command Prompt Here", then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\System32\cmd.exe" /k ver
So, just be careful, if you start "cmd.exe" from a shortcut that contains a "/c" in the "Target" field (unlikely), then the test in the previous example will fail to test this case properly.

Resources