The following command
#Set "installed_version=" & #(FOR /F %a IN ('curl 192.168.1.151:5000/getversion') DO #SET installed_version=%a)
is failing when running on a Windows agent in Teamcity with error
) was unexpected at this time. Process exited with code 255
However, the same command runs smoothly when running on a command prompt on my local Windows 10 machine. The teamcity agent is a Windows Server 2008 R2, version 6.1.
What am I doing wrong?
It turns out, % has to be escaped when in a bat file, so it should be %%.
At the same time, in Kotlin DSL % also needs to be escaped, so we end up with %%%%.
Related
The following illustrates a problem I found using for /f %l in ('<command>') do #(echo %l). (/f is the for command's parameter for "iterating and file parsing.") This works as expected when <command> is cd or chdir, but not when <command> is pushd:
C:\>cd
C:\
C:\>for /f %l in ('cd') do #(echo %l)
C:\
C:\>chdir
C:\
C:\>for /f %l in ('chdir') do #(echo %l)
C:\
C:\>pushd Windows
C:\Windows>pushd
C:\
C:\Windows>for /f %l in ('pushd') do #(echo %l)
C:\Windows>pushd > nul
C:\Windows>
I would expect the last command to print C:\ but it does not execute the do block at all. I added pushd > nul to check that pushd prints to stdout.
How can I process the output of pushd in a for /f loop?
Information about command processing by FOR /F
The usage of a for /F loop with a command enclosed in ' or in ` on using usebackq results in starting in background one more command process using %ComSpec% /c and the command appended as additional argument(s).
The usage of for /f %l in ('pushd') do #(echo %l) results in background execution of:
C:\Windows\System32\cmd.exe /c pushd
That can be seen by downloading, extracting and running the free Windows Sysinternals tool Process Monitor as administrator which logs the execution of two cmd.exe processes with different process identifiers on running the commands as posted in the question. There must be double clicked on any line in log of Process Monitor of second cmd.exe in the middle of the log to open the Event Properties window and selected the second tab Process to see the Command Line which was used by first cmd.exe to start the second cmd.exe for the execution of the command pushd.
There cannot be executed just a single command with a for /F loop. There can be executed an entire command line which can even have multiple commands. But it is necessary to take into account all the information given by the usage help of cmd output on running cmd /? in a command prompt window on using a complex command line with for /F and processing its output as written to handle STDOUT of in background started cmd.exe.
Command operators like &, && and || as well as redirection operators like |, 2> and 2>&1 in the command line to execute by for /F are processed by two cmd.exe, first the one executing the entire for /F loop and another one started in background with the command line of which output is of interest. That is the reason why many for /F loops with a complex command line are with the escape character ^ left to each & and | and > in the command line to get these characters interpreted literally by cmd.exe parsing and executing the entire for /F loop while being interpreted as command/redirection operators by the second cmd.exe started in background which is really executing the command line.
Information about output of PUSHD
The Windows command PUSHD outputs on execution without any directory path the list of directory paths pushed on stack of current command process.
There can be executed in a command prompt window following commands:
cd /D %SystemDrive%\
pushd %SystemRoot%
pushd inf
pushd
popd
popd
The fifth command pushd results usually for typical Windows installations in the output:
C:\Windows
C:\
But there is nothing output by using as fifth command instead of pushd the command line:
for /F "delims=" %I in ('pushd') do #echo %I
The reason is the execution of pushd by one more cmd.exe started in background which has no directory paths pushed on its stack. The internal command PUSHD does not output anything at all for that reason to handle STDOUT of in background started cmd.exe.
The command process running for /F cannot capture any output text. The for /F loop cannot process therefore any line after cmd.exe started in background finished the execution of pushd and closed itself.
How to process the directory paths pushed on stack?
It would be necessary to use the following command lines in the command prompt window to process the directory paths pushed on stack of the current command process:
pushd >"%TEMP%\DirectoryList.tmp"
if exist "%TEMP%\DirectoryList.tmp" for /F "usebackq delims=" %I in ("%TEMP%\DirectoryList.txt") do #echo %I
del "%TEMP%\DirectoryList.tmp" 2>nul
The redirection of the output of PUSHD executed by the command process which executed also the two pushd command lines before into a temporary file makes it possible to process the directory paths pushed on stack of current command process.
The for /F option usebackq is necessary to get the string inside " interpreted as file name of which lines to process by the FOR loop and not as string to process.
The for /F option delims= is necessary to define an empty list of string delimiters as a directory path can contain one or more spaces. There is by default split up a line into substrings using normal space and horizontal tab as string delimiters and assigned to the loop variable is just the first space/tab delimited string instead of the entire directory path. The line splitting is turned off by the definition of an empty list of delimiters. The entire directory path is assigned therefore always to the loop variable in this case with processing always full directory paths never starting with the default end of line character ; as the first character is always either a drive letter or a backslash in case of a UNC directory path.
Why does the command CD work with a FOR /F loop?
The command CD works also with for /F "delims=" %I in ('cd') do #echo %I because of cmd.exe calls the Windows kernel library function CreateProcess on starting the additional command process for execution of a command specified as set of a for /F loop with value NULL for the function parameter lpCurrentDirectory. The current directory of in background started cmd.exe is set by CreateProcess for that reason with the current directory of the command process executing the for /F command line. Both running command processes have the same current directory during the execution of the command of a for /F loop.
Information about environment variable ComSpec
ComSpec is an environment variable defined by default with %SystemRoot%\system32\cmd.exe (with s at beginning of System32 instead of S as the folder name is in real by default) as system environment variable stored in Windows registry under the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment.
It is really not advisable to ever modify or even delete the environment variable ComSpec neither in local environment of a running process nor in the Windows registry. That would cause a lot of programs to stop working normally as lots of executables depend internally on the correct definition of this environment variable including cmd.exe itself.
The reason is that many applications and scripts use internally the function system which uses the environment variable ComSpec to start on Windows cmd.exe for execution of a command line.
There are many batch files running internal command ver of cmd.exe to get the Windows version like:
for /F "tokens=2 delims=[]" %%G in ('ver') do for /F "tokens=2" %%H in ("%%G") do echo %%H
That works only for Windows NT based Windows versions using cmd.exe as command processor and not for older Windows versions using COMMAND.COM like Windows 95/98/ME for processing a batch file. It works only with enabled command extensions which are enabled by Windows default, but can be disabled by command setlocal DisableExtension in a batch file, on starting cmd.exe with /E:OFF or by a registry value which should be really never used and therefore not written here. The command ver must be really executed by %SystemRoot%\System32\cmd.exe because of in real is output the version of cmd.exe and not the version of Windows.
However, that command line is very good to demonstrate what happens on usage of for /F if the environment variable ComSpec is not defined in environment of cmd.exe on running the batch file with the two for /F loops.
ComSpec usage by cmd.exe on Windows XP
On Windows XP is always called C:\WINDOWS\system32\cmd.exe /c ver even on doing following:
Copying cmd.exe to the directory F:\Temp\system32.
Starting F:\Temp\system32\cmd.exe with a double click in Windows Explorer.
Running set ComSpec=F:\Temp\system32\cmd.exe and set SystemRoot=F:\Temp and set SystemDrive=F: and set windir=F:\Temp.
Verifying with echo %__APPDIR__% that F:\Temp\system32\ is output.
Running the batch file with the command line as posted above.
That can be seen with Process Monitor v3.61 on Windows XP x86.
There can be even modified the local environment variable PATH to begin with F:\Temp\system32 instead of C:\WINDOWS\system32 or the local environment variable ComSpec is deleted with set ComSpec=. The Windows Command Processor of Windows XP in directory F:\Temp\system32 calls nevertheless always C:\WINDOWS\system32\cmd.exe with the option /c and the command ver on running the batch file immediately after closing the batch file containing just the single command line in the text editor.
There cannot be seen in Process Monitor even a Windows registry access by cmd.exe of Windows XP to get any directory path.
Please read further why cmd.exe of Windows XP in a different directory than %SystemRoot%\System32\cmd.exe calls nevertheless the command processor executable in Windows system directory even after modification of local environment variable ComSpec or its deletion.
ComSpec usage of cmd.exe on Windows Vista/7/8/8.1/10/11
The same procedure as described above for Windows XP can be executed also on Windows 7 x64 and newer 64-bit Windows versions.
The double clicked 64-bit F:\Temp\system32\cmd.exe copied from C:\Windows\System32 outputs on Windows 7 and currently latest Windows 11 22H2 first:
The system cannot find message text for message number 0x2350 in the message file for Application.
(c) Microsoft Corporation. All rights reserved.
Note: The copyright message line depends on version of cmd.exe. The output above is from cmd.exe of version 10.0.22621.963 (Windows 11 22H2).
The Windows Command Processor cmd.exe of version 6.1.7601 of Windows 7 outputs additionally the line:
Not enough storage is available to process this command.
The execution of the internal command ver executed in the command prompt window opened with a double click on F:\Temp\System32\cmd.exe fails on Windows 7 and all later Windows versions up to currently latest Windows 11 22H2 which is the reason for the strange output on starting F:\Temp\System32\cmd.exe with a double click.
There can be redefined also the environment variables as described above and done on German Windows XP by me on my tests. A verification of the output of echo %__APPDIR__% works and shows F:\Temp\system32\ as expected. So, it works to access the string value of the internal dynamic variable of cmd.exe even on executed cmd.exe is not in the directory %SystemRoot%\System32.
But the batch file execution from within the command prompt of F:\Temp\system32\cmd.exe as on Windows XP results in no output at all.
In log of Process Monitor v3.70 or a newer Process Monitor version can be seen that on Windows 7 and Windows 11 22H2 is executed F:\Temp\System32\cmd.exe /c ver. That means it is indeed possible that another cmd.exe is executed instead of C:\Windows\System32\cmd.exe on Windows 7 and newer Windows versions.
But why is no version output?
Well, the execution of ver results in the output of the error message:
The system cannot find message text for message number 0x2350 in the message file for Application.
64-bit cmd.exe is not working in F:\Temp\system32 at all.
The usage of 32-bit cmd.exe copied from C:\Windows\SysWOW64 to F:\Temp\system32 makes no difference. The same error messages are output already on starting F:\Temp\system32\cmd.exe and on running next ver or the batch file after modification of local environment variable ComSpec.
Conclusion: cmd.exe of Windows Vista and newer versions are not fully working on being stored outside the appropriate system directory %SystemRoot%\System32 or %SystemRoot%\SysWOW64 while cmd.exe of Windows XP works fine in any directory.
Caching of ComSpec value
I found out with lots of further tests that the string value of the environment variable ComSpec is indeed used to find cmd.exe to run command ver on execution of the batch file with the for /F loop. But there is a caching mechanism on Windows Vista and newer Windows versions.
There must be run immediately set ComSpec=F:\Temp\system32\cmd.exe after starting F:\Temp\system32\cmd.exe before running the batch file. This results in calling F:\Temp\system32\cmd.exe /c ver. If there is next executed set ComSpec=C:\Windows\System32\cmd.exe to redefine the variable with correct value and run the batch file once again, there is nevertheless run now not working F:\Temp\system32\cmd.exe /c ver.
The same caching mechanism can be seen on starting F:\Temp\system32\cmd.exe, then running the batch file resulting in calling in background C:\Windows\System32\cmd.exe /c ver, next running set ComSpec=F:\Temp\system32\cmd.exe and running now the batch file again. There is executed once again C:\Windows\System32\cmd.exe /c ver although the value of the environment variable ComSpec is now F:\Temp\system32\cmd.exe.
It looks like cmd.exe of Windows Vista/7/8/8.1/10/11 reads the value of ComSpec only once and keeps its value in memory for further usage without reading the environment variable a second time on string value for the default command interpreter being already in its internal memory.
That is quite clever in my opinion. The string value of ComSpec is read only once from the environment variable on first usage and then is used that string internally on further usage because of the value of the environment variable ComSpec changes usually never as long as cmd.exe is running.
It looks like cmd.exe of Windows XP has nearly the same caching mechanism for the string value of the environment variable ComSpec. The difference is that cmd.exe of Windows XP reads the value of ComSpec already on starting it and not on first usage and so all changes done on local environment variable ComSpec of an already running cmd.exe have no effect on the execution of one more cmd.exe on processing a for /F loop with a command line to execute, capturing the output and processing it as I could find out with further tests on German Windows XP.
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?
I am trying to make a batch file that will check certain SVN repositories for updates each morning. I want to store local repository names in a file (SVN_check_list.txt) and have the console show me the list. My code, posted below, works when I just run the batch file:
#echo off
echo Checking for updates...& echo.
for /F %%A in (SVN_check_list.txt) do (
echo Checking '%%A'
svn status %%A -u )
pause
However, when I try to run it through Windows Task Scheduler (while I am logged in), it runs the code but does not display anything until the 'pause' at the end. When I turn echo on, it shows the commands (svn status -u) but not the output. How can I make this batch file display the outputs of the svn status command even when I run it with task scheduler?
Try passing cmd as the Program/Script to run in Scheduler with arguments /k "C:\My Batch File Folder\MyScript.bat"
This will launch the console.
I found this solution that seems to work: Run a batch file with Windows task scheduler
Basically:
Action: Start a program
Program/script: cmd
Add arguments: /k "C:\Users\tanderson\Documents\setup.bat"
Start in: C:\Users\tanderson\Documents (No quotes)
I am trying to call runScript.bat of Openscript (OracleATS) from Jenkins. There is one command to generate GUID in runScript.bat
for /f %%i in ('%~d0%~p0guidgen.exe') do set GUID=%%i
This command is always failing with error,
'C:\OracleATS\openScript\guidgen.exe' is not recognized as an internal or external command,
operable program or batch file.
It runs fine when I call runScript.bat from command prompt.
What could be the possible reason for failure at this point?
The issue was with the registry setting on the machine where I was running the bat file.
More details : Command Line FOR /F Fails
I am new to batch. So I was playing with commands and I found that I dont undarstand how to write multiple lines of commands in batch here is example.
start cmd.exe /k "ipconfig && whoami && getmac && netplwiz "
%windir%\system32\wuapp.exe
This will work fine but I was thinking how to make it easier for reading and make it with comments and I cant figure out how to do it. Here is what I tried.
start cmd.exe ^
/k "ipconfig ^
&& whoami ^
&& getmac ^
&& netplwiz "
%windir%\system32\wuapp.exe
So this does not work I know this symbol ^ is continuation of line. It does work for ipconfig to showup in cmd but rest commands are ignored.
Here is example with multiple lines and it works fine
set wind=%windir%
set winsys=%windir%\system32
REM Checks if any browsers are currently running. If so, they will be terminated.
start /min /wait wscript.exe %~dp0CheckforProcesses.vbs
REM Uninstalling Java JRE 6 Update 29
start /wait msiexec.exe /X{26A24AE4-039D-4CA4-87B4-2F83216029FF} /quiet
REM Uninstalling Java JRE 7 Update 55
start /wait msiexec.exe /X{26A24AE4-039D-4CA4-87B4-2F83217055FF} /quiet
REM Uninstalling Java JRE 7 Update 65
start /wait msiexec.exe /X{26A24AE4-039D-4CA4-87B4-2F03217065FF} /quiet
REM Installing Java JRE 7 Update 65
msiexec /i "%~dp0JRE\765\jre7_65.msi" /norestart /qn
I hope my question is clear and I am sorry if not. I know this commands in my example not useful in that contest , but this is not the point. The point I want to use multiple lines for better reading batch file code and not have 300 characters in one line (I hope it makes sense).
In my head I have only one explanation that some commands is have to be written in one line and there is no other way around.
Thank you for your time
Use the & Symbol.
See here: http://commandwindows.com/command1.htm
For example:
#echo off
ipconfig
whoami
getmac
netplwiz
echo\
echo Press the Space bar to close this window.
pause > nul
Edit: I believe a line break may also work.
Edit 2: added example.