I'm encountering a syntax error when trying to execute a batch script file (*.cmd) with an additional script parameter, directly in a CMD instance.
This command works without any issues:
cmd.exe /C " START /W /MIN "Title" "_Path with spaces.cmd" "
However, when I try to pass a parameter to the script file, like this:
cmd.exe /C " START /W /MIN "Title" "_Path with spaces.cmd" "file parameter one" "
I get the error:
"_Path" is not recognized as an internal or external command, operable program or batch file.
Clearly there is a syntax error related to the usage of double quotes (maybe I'm missing to add additional double quotes somewhere else and/or to escape them), since the error message stops printing the file name on the first white space found.
How can I correct the syntax to successfully pass the parameter "file parameter one" to the script file "_Path with spaces.cmd"?
START
command is necessary since I want to minimize the newly created CMD window where the script file runs, with the /MIN
switch.There should be executed a Windows batch file from within a Command Prompt window or from within a PowerShell console window which runs another batch file of which output should not be seen in the current console window.
That can be achieved by adding to the existing batch file:
setlocal EnableExtensions DisableDelayedExpansion
call "_Path with spaces\Other Batch.cmd" "file parameter one" 1>NUL 2>NUL
endlocal
There should be used the following three command lines if the batch file with spaces in the fully qualified file name is for sure always in the same directory as the batch file calling it:
setlocal EnableExtensions DisableDelayedExpansion
call "%~dp0Other Batch.cmd" "file parameter one" 1>NUL 2>NUL
endlocal
That simple solution works as long as neither the fully qualified batch file name nor the file name passed to the batch file contains one or more literally to interpret %
characters and the other batch file does not contain the command exit
without option /B
.
An alternative and always working solution is:
@start "Title" /MIN /WAIT %ComSpec% /D /S /C ^""_Path with spaces\Other Batch.cmd" "file parameter one"^"
That solution using an additional cmd.exe
for processing Other Batch.cmd
with cmd.exe
processing the main batch file halting the batch file processing until the additionally started cmd.exe
closed itself works even with one or more literally to interpret percent characters in one of the two file names and even if the command exit
without option /B
is used in Other Batch.cmd
.
A Command Prompt window is a running instance of the Windows Command Processor %SystemRoot%\System32\cmd.exe
which is usually started from the Windows shell (explorer.exe
) by calling the Windows kernel library function CreateProcess with a filled out STARTUPINFO structure.
The parameters for the function call and the values for the structure are loaded in this case from the properties of the shortcut file %APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\Command Prompt.lnk
. The shortcut property Target is the string passed with function parameter lpCommandLine
(long pointer to command line string) to CreateProcess
. The shortcut property Start in is the string passed with function parameter lpCurrentDirectory
(long pointer to current working directory string) to CreateProcess
. It is quite easy to see which shortcut property on which tab is for which function parameter or structure element after reading the documentation for the function CreateProcess
and the structure STARTUPINFO
. If cmd.exe
is executed from Windows shell without using the shortcut file, the console properties are loaded from Windows registry key HKEY_CURRENT_USER\Console
.
The start of Windows PowerShell %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
is usually done by the Windows shell by calling CreateProcess
with the parameters defined by the shortcut file %APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk
.
The Microsoft developer blog Understanding Windows Console Host Settings offers more information about the settings used on starting a console application.
The Windows kernel function CreateProcess
is also called by cmd.exe
and powershell.exe
whenever an executable must be run as entered by a user directly in the console window on a command line, or read from the argument strings list on cmd.exe
or powershell.exe
being started with appropriate arguments, or read from a script file during processing of a Windows batch file or PowerShell script.
The execution of cmd /?
in a Command Prompt or PowerShell console window results in output of the usage help of the Windows Command Processor which explains how a command line consisting of one or more argument strings and perhaps even command and redirection operators after option /C
(run command line and close) or option /K
(run command line and keep running) is interpreted by cmd.exe
. There are several criteria which must be considered on instructing cmd
running a complex command line.
In a Command Prompt window – not in a PowerShell console window – can be executed call /?
for information about how a batch file can call another batch file by using the cmd
internal command CALL and how arguments can be referenced from within a batch file. The execution of start /?
in a Command Prompt window outputs the usage help for the cmd
internal command START which can be used to run an executable by calling CreateProcess
with different values for some function parameters and some structure elements.
The command START modifies some parameters on calling the function CreateProcess
for the execution of an executable depending on the used options of command START in comparison to running the executable during batch file processing without usage of command START.
START without the options /B
and /WAIT
results in starting the executable as separate process with its own STDIN, STDOUT, STDERR handles which is executed parallel to cmd.exe
as detached process and with its own console window on started executable is a console application. The Windows Command Processor immediately continues processing the batch file after the start of the executable in this case. It is possible that cmd.exe
terminates itself while the started executable is still running and continues running.
START with option /WAIT
results also in starting the executable as separate process with its own STDIN, STDOUT, STDERR handles and creation of a new console window on being a console application. But cmd.exe
does not continue processing the batch file. It waits for the self-termination of the started executable before it continues processing of the batch file.
START with option /B
results in starting the executable with STDIN, STDOUT, STDERR handles of cmd.exe
without the creation of a new console window on being a console application. The process is executed parallel to cmd.exe
which continues processing the batch file. But the started executable is not completely detached from the cmd
process as it shares its handles with it. It becomes more or less a child process of cmd.exe
which in general is terminated when the cmd
process terminates which started the executable with START and option /B
. Starting multiple console applications with START and option /B
which all output to STDOUT and STDERR causes a chaotic list of output text in the console window.
There should be read my answer on How to call a batch file that is one level up from the current batch file directory? It explains briefly the four methods which exist for running a batch file from within a batch file and what are the main differences.
The called batch file could delete environment variables or redefine existing environment variables. It could also change the current working directory. If that is possible but not wanted for the main batch file execution, the commands SETLOCAL and ENDLOCAL should be used as shown above.
The command SETLOCAL
This is always done by the command SETLOCAL independent on being run with no, one or two parameters.
The command ENDLOCAL
This is done also by the Windows Command Processor cmd.exe
implicitly for each SETLOCAL executed during processing of a batch file for which no ENDLOCAL execution was done explicitly before exiting the processing of a batch file. Many batch files using SETLOCAL somewhere at top do not contain ENDLOCAL somewhere at the end for that reason.
The usage of SETLOCAL before calling the other batch file and ENDLOCAL after the batch file call makes sure that the execution environment (environment variables and current working directory) of the main batch file is not modified by the other batch file.
There are just two commands in the called batch file which could affect the further execution of the main batch file other than pause
.
echo on
is used in the called batch file to turn on the command echo mode. In this case it would be additionally necessary to insert @echo off
after the call
of the other batch file for turning off again the command echo mode.exit
without option /B
is used in the called batch file to instruct cmd.exe
processing the batch file to immediately exit independent on calling hierarchy and if cmd.exe
was started with option /C
or option /K
or none of these two options. In this case the main batch file is not further processed too. That is the reason nearly no batch file should contain ever the command exit
without option /B
as it makes the usage of this batch file from within another batch file more complicated than necessary. The exception is a batch file of which processing is started by an installer executable which deletes itself with the last command line in the batch file to prevent an error message output by cmd.exe
on batch file suddenly not existing anymore.The first solution for the second point is modifying the called batch file and removing exit
on being completely unnecessary and counterproductive on last line of the batch file or inserting the option /B
after exit
on being used in other lines of the called batch file for an immediate exit of the processing of this batch file without exiting the command process.
The second solution is the one asked for. The command START is used to process the batch file by one more cmd.exe
as separate command process and wait for its self-termination which can be also caused by the command exit
without option /B
in the other batch file.
start "Title" /MIN /WAIT %ComSpec% /D /S /C ^""_Path with spaces\Other Batch.cmd" "file parameter one"^"
There is started one more command process by referencing the system environment variable ComSpec
which is defined by Windows default with %SystemRoot%\system32\cmd.exe
by cmd.exe
processing the main batch file with calling the Windows kernel function CreateProcess
. There is created a new console window for this additional command process which is opened minimized. The cmd.exe
instance processing the main batch file waits for the self-termination of the additionally started cmd.exe
before it continues processing of the main batch file.
There are passed to this additional command process the options /D
for ignoring the AutoRun
registry value and the option /S
to interpret everything after option /C
as one command line with removal of the first and the last "
from this command line string.
The two double quotes surrounding the entire command line with the fully qualified batch file name enclosed in "
and the file name without or with path passed to the batch file also enclosed in "
as required for file names with one or more spaces or one of these characters &()[]{}^=;!'+,`~
are escaped in the batch file with caret character ^
to be interpreted as literal characters by cmd.exe
processing the main batch file. That is necessary if one of the two file names contains an ampersand. cmd.exe
processing the batch file should parse "_Path with spaces\Other Batch.cmd"
as one double quoted argument string and "file parameter one"
as another double quoted argument string to interpret spaces and these characters &()[]{}^=;!'+,`~
inside the two file name strings also literally on processing the batch file like the later executed additional cmd.exe
during the main batch file processing.
The reason for using ^
left to first and last "
of the command line parsed to the additional cmd.exe
on execution of the main batch file is easier to understand with an example.
There is the directory C:\Temp
which contains:
A batch file with name Main.cmd
with the single command line:
@start "Other Batch" /MIN /WAIT %ComSpec% /D /S /C ""%~dp0Development & Test 100%% (!)\Other.cmd" "file parameter one""
A batch file with name Test.cmd
with the single command line:
@echo Arguments: %*& pause
A subdirectory with name Development & Test 100% (!)
with a batch file Other.cmd
with the command line:
@echo First argument is: %1& pause
Open a Command Prompt window, run cd /D C:\Temp
and execute now Main.cmd
.
What can be seen?
There is for a truly short time opened minimized another console window with Other Batch
as window title. It is impossible to see what is output in this console window as it closes immediately.
There is displayed in the Command Prompt window the text:
Arguments: 100% (!)\Other.cmd" "file parameter one""
Press any key to continue . . .
What happens here is that cmd.exe
processing C:\Temp\Main.cmd
interprets the command line as a line with two commands because of &
outside a double quoted argument string as:
@start "Title" /MIN /WAIT C:\WINDOWS\system32\cmd.exe /D /S /C ""C:\Temp\Development
Test 100%% (!)\Other.cmd" "file parameter one""
The command START is executed first by cmd.exe
processing the batch file C:\Temp\Main.cmd
which results in starting one more cmd.exe
which fails to find an executable or script with name Development
in the directory C:\Temp
, outputs an error message in minimized console window and closes itself.
Next is executed by cmd.exe
processing the batch file C:\Temp\Main.cmd
the second command Test by searching first in the current directory C:\Temp
for such a file. It finds by chance Test.cmd
and continues the batch file processing with processing of C:\Temp\Test.cmd
. This batch file outputs on processing what it gets passed as arguments and then pauses the batch file processing until a key is pressed by the user.
Now let us fix this unwanted behavior by modifying the line in C:\Temp\Main.cmd
to:
@start "Other Batch" /MIN /WAIT %ComSpec% /D /S /C ^""%~dp0Development & Test 100%% (!)\Other.cmd" "file parameter one"^"
There are just ^
added left to first and last "
of the command line to execute by the additional started cmd.exe
.
The execution of Main.cmd
in C:\Temp
in the Command Prompt windows results now in:
Other Batch
as window title is opened and displayed minimized.cmd.exe
is waiting for self-termination of the started second cmd.exe
.Open the console window with window title Other Batch
and there can be seen:
First argument is: "file parameter one"
Press any key to continue . . .
Press any key in this console window and the window closes. The initial Command Prompt window shows now the prompt and there can be entered the next command.
This small example demonstrates how difficult it is to write a batch file with a command line which should always work for any file/folder name which is interpreted during the batch file execution by more than one cmd.exe
. The syntax rules of all cmd.exe
must be considered on writing the command line in the main batch file.
It is in most use cases better to use in C:\Temp\Main.cmd
:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
call "%~dp0Development & Test 100%%%% (!)\Other.cmd" "file parameter one" 0<NUL 1>NUL 2>NUL
@echo off
endlocal
The single %
in the awful subdirectory name must be escaped with one more %
in the batch file to be processed literally by cmd.exe
processing C:\Temp\Main.cmd
. But the usage of the command CALL results in parsing the command line a second time by cmd.exe
which would remove the single %
and the batch file Other.cmd
would not be found anymore in the directory C:\Temp\Development & Test 100 (!)
because of this directory with no %
does not exist at all. The solution is %%%%
which becomes %%
on first parsing of the command line and finally just %
on second parsing because of CALL.
0<NUL
results in no STDIN available on processing C:\Temp\Development & Test 100% (!)\Other.cmd
and therefore pause
does not result in halting the batch file execution until a key is pressed by the user.
The execution of Other.cmd
from C:\Temp
with the command line "Development & Test 100% (!)\Main.cmd
would also fail if C:\Temp\Main.cmd
with the above command lines would be moved into the directory C:\Temp\Development & Test 100% (!)
and the third command line would be modified to:
call "%~dp0Other.cmd" "file parameter one" 0<NUL 1>NUL 2>NUL
The moved batch file is executed with "Development & Test 100% (!)\Main.cmd"
from the directory C:\Temp
.
The Windows Command Processor first parses this command line and interprets it as:
call "F:\Temp\Development & Test 100% (!)\Other.cmd" "file parameter one"
That looks right. But the command CALL results in parsing this command line a second time and it becomes now:
call "F:\Temp\Development & Test 100 (!)\Other.cmd" "file parameter one"
The character %
in directory name is missing now after second command line parsing before the execution of the command CALL.
In such uses cases with one of the file names could contain by chance a percent sign as part of the file name and not as part of an environment variable, loop variable or argument string reference, it is better to use the solution with command START instead of a solution with command CALL.