Pass path with spaces as parameter to bat file
Interesting one. I love collecting quotes about quotes handling in cmd/command.
Your particular scripts gets fixed by using %1 instead of "%1" !!!
By adding an 'echo on' ( or getting rid of an echo off ), you could have easily found that out.
I think the OP's problem was that he wants to do BOTH of the following:
- Pass a parameter which may contain spaces
- Test whether the parameter is missing
As several posters have mentioned, to pass a parameter containing spaces, you must surround the actual parameter value with double quotes.
To test whether a parameter is missing, the method I always learned was:
if "%1" == ""
However, if the actual parameter is quoted (as it must be if the value contains spaces), this becomes
if ""actual parameter value"" == ""
which causes the "unexpected" error. If you instead use
if %1 == ""
then the error no longer occurs for quoted values. But in that case, the test no longer works when the value is missing -- it becomes
if == ""
To fix this, use any other characters (except ones with special meaning to DOS) instead of quotes in the test:
if [%1] == []
if .%1. == ..
if abc%1xyz == abcxyz
Use "%~1"
. %~1
alone removes surrounding quotes. However since you can't know whether the input parameter %1
has quotes or not, you should ensure by "%~1"
that they are added for sure. This is especially helpful when concatenating variables, e.g. convert.exe "%~1.input" "%~1.output"
"%~1" will work most of the time. However there are a few things you need to note for this:
- It's not supported in Windows NT 4.0. You need Windows 2000 or later. (If you are coding a script compatible with old OS, beware.)
- It does not make parameters secure and sanitized. My observation is that there is no way to properly sanitize the command line arguments in CMD scripts.
To demonstrate second point, let me give an example:
REM example.cmd
ECHO %~1
Run with example.cmd dummy^&DIR
. The ampersand is escaped here ( ^&
) to prevent shell from interpreting as a command delimiter, so that it becomes part of the argument passed to the script. The DIR is interpreted as a command inside the sub-shell running the script, where it shouldn't.
Quoting it might work some time, but still insecure:
REM example2.cmd
SETLOCAL EnableExtensions EnableDelayedExpansion
SET "arg1=%~1"
ECHO "%~1"
ECHO !arg1:"=!
example2.cmd foo^"^&DIR^&^"bar
will break it. DIR command will be run two times, one right after SET and the other right after the first ECHO. You see that the "%~1"
you think is quoted well gets unquoted by the argument itself.
So, no way to make parsing arguments secure.
(EDIT: EnableDelayedExpansion
doesn't work in Windows NT 4 either. Thanks to the info here: http://www.robvanderwoude.com/local.php)