Pass path with spaces as parameter to bat file

Viewed 211958

I have a simple bat script that copies files from an known directory to a directory given by the user. How can I pass the path (it might contain spaces) to my script and use it with the xcopy command?


In my code i have the following

:READ_PWA_PATH
    if "%1" == "" ( 
        rem Set default path
        set PWA_PATH="C:\Program Files\PWA"
        rem
        echo You have not specified your PWA url.
        echo Default will be assumed: C:\Program Files\PWA. 
        choice /C:YN /M:"Do you wish to continue [Y] or cancel the script [N]?"
            IF ERRORLEVEL ==2 GOTO CANCEL
            IF ERRORLEVEL ==1 GOTO READ_WSS_SERVER_EXTENSIONS_PATH
        GOTO END
    ) else (
        set PWA_PATH=%1
    )

If I simply call the script I get the following error:

C:\Projects\Setup>install.cmd "C:\program files (x86)"

-----------------
SETUP SCRIPT
-----------------

files was unexpected at this time.
C:\Projects\Setup>
9 Answers

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

If you have a path with spaces you must surround it with quotation marks (").

Not sure if that's exactly what you're asking though?

@echo off
setlocal enableextensions enabledelayedexpansion

if %1=="" (     
        rem Set default path
        set PWA_PATH="C:\Program Files\PWA"
        rem
        echo You have not specified your PWA url.
        echo Default will be assumed: C:\Program Files\PWA.     
        choice /C:YN /M:"Do you wish to continue [Y] or cancel the script [N]?"
                IF ERRORLEVEL ==2 GOTO CANCEL
                IF ERRORLEVEL ==1 GOTO READ_WSS_SERVER_EXTENSIONS_PATH
        GOTO END
    ) else (
        set PWA_PATH=%1
        @echo !PWA_PATH! vs. %1
        goto end
    )
:READ_WSS_SERVER_EXTENSIONS_PATH
echo ok
goto end
:CANCEL
echo cancelled
:end
echo. final %PWA_PATH% vs. %1

As VardhanDotNet mentions, %1 is enough.

"%1%" would add quotes around quotes: ""c:\Program Files\xxx"" which means:

  • 'empty string' (""),
  • followed by 'c:\Program',
  • followed by the "unexpected here" 'Files\xxx',
  • followed by an empty string ("")

Note however that if you need to use PWA_PATH within your IF clause, you need to refer if as !PWA_PATH! (hence the enabledelayedexpansion as the beginning of the script)

Suppose you want to backup a database by executing a batch file from within a C# code. Here is a fully working solution that deals with blank spaces inside the path. This works in Windows. I have not tested it with mono though.

C# code:

        public bool BackupDatabase()
    {
        bool res = true;
        string file = "db.bat";
        if (!File.Exists(file)) return false;

        BackupPaths.ForEach(path =>
        {
            Directory.CreateDirectory(path);

            string filePath = Path.Combine(path, string.Format("{0}_{1}.bak", Util.ConvertDateTimeToFileName(false), DatabaseName));
            Process process = new Process();
            process.StartInfo.FileName = file;
            process.StartInfo.Arguments = string.Format(" {0} {1} \\\"{2}\\\""
                , DBServerName
                , DatabaseName
                , filePath);

            process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            try
            {
                process.Start();
                process.WaitForExit();
            }
            catch (Exception ee)
            {
                Logger.Log(ee);
                res = false;
            }
        });
        return res;
    }

and here is the batch file:

@echo OFF
set DB_ServerName=%1
set Name_of_Database=%2
set PathToBackupLocation=%3

echo Server Name = '%DB_ServerName%'
echo Name of Database = '%Name_of_Database%'
echo Path To Backup Location = '%PathToBackupLocation%'

osql -S %DB_ServerName% -E -Q "BACKUP DATABASE %Name_of_Database% TO DISK=%PathToBackupLocation%"

In a special case scenario, where you want to always default to the current directory always, OR, default to the current directory only if a parameter was not passed in, you can use %CD%.

As found per this answer on Server Fault:

Windows maintains the current directory in the psuedo-environment variable %CD%.

Check out that post for a great example and how your can easily test it directly via the command line.

In my case, I an an app (myapp.exe) that I needed to call with a command-line flag --dir=, like:
myapp --dir=<path-to-desired-directory>.

Since I always wanted the flag to always reference whichever directory I called the app from, I could make a batch file (mybat.bat) to automatically capture my current path, and open the app with it.

mybat . worked when mybat.bat had the following contents:
myapp --dir=%1

Which was great, but being able to leave off the . was even better.
mybat works when I changed the contents to:
myapp --dir=%CD%

Related