Spaces and Parenthesis in windows PATH variable screws up batch files

14

7

So, my path variable (System->Adv Settings->Env Vars->System->PATH) is set to:

C:\Python26\Lib\site-packages\PyQt4\bin;
%SystemRoot%\system32;
%SystemRoot%;
%SystemRoot%\System32\Wbem;
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;
C:\Python26\;
C:\Python26\Scripts\;
C:\cygwin\bin;
"C:\PathWithSpaces\What_is_this_bullshit";
"C:\PathWithSpaces 1.5\What_is_this_bullshit_1.5";
"C:\PathWithSpaces (2.0)\What_is_this_bullshit_2.0";
"C:\Program Files (x86)\IronPython 2.6";
"C:\Program Files (x86)\Subversion\bin";
"C:\Program Files (x86)\Git\cmd";
"C:\Program Files (x86)\PuTTY";
"C:\Program Files (x86)\Mercurial";
Z:\droid\android-sdk-windows\tools;

Although, obviously, without the newlines.

Notice the lines containing PathWithSpaces - the first has no spaces, the second has a space, and the third has a space followed by a parenthesis.

Now, notice the output of this batch file:

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\>vcvars32.bat
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>"C:\Program Files (x86
)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
\What_is_this_bullshit_2.0";"C:\Program was unexpected at this time.
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>      set "PATH=C:\Pro
gram Files\Microsoft SDKs\Windows\v6.0A\bin;C:\Python26\Lib\site-packages\PyQt4\
bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\
WindowsPowerShell\v1.0\;C:\Python26\;C:\Python26\Scripts\;C:\cygwin\bin;"C:\Path
WithSpaces\What_is_this_bullshit";"C:\PathWithSpaces 1.5\What_is_this_bullshit_1
.5";"C:\PathWithSpaces (2.0)\What_is_this_bullshit_2.0";"C:\Program Files (x86)\
IronPython 2.6";"C:\Program Files (x86)\Subversion\bin";"C:\Program Files (x86)\
Git\cmd";"C:\Program Files (x86)\PuTTY";"C:\Program Files (x86)\Mercurial";Z:\dr
oid\android-sdk-windows\tools;"

or specifically the line:

\What_is_this_bullshit_2.0";"C:\Program was unexpected at this time.

So, what is this bullshit?

Specifically:

  • Directory in path that is properly escaped with quotes, but with no spaces = fine
  • Directory in path that is properly escaped with quotes, and has spaces but no parenthesis = fine
  • Directory in path that is properly escaped with quotes, and has spaces and has a parenthesis = ERROR

Whats going on here? How can I fix this? I'll probably resort to a junction point to let my tools still work as workaround, but if you have any insight into this, please let me know :)

user30404

Posted 2010-03-13T23:06:37.803

Reputation:

Based on my understanding of the issues at hand, the above answer is the correct one, and it relies on taking into account that SET is the command, and PATH is part of its argument, the balance of which is the new PATH string. So, IMO, it's not that it is sparsely documented, but that it's more like an obscure edge case. I've just spent a couple of hours on this issue. – David A. Gray – 2018-07-23T07:53:43.703

Answers

14

This can happen if there are unescaped parentheses in a line inside a "block" (which also uses parentheses for delimiting).

You can usually fix it by turning on delayed expansion and use variables with !var! instead of %var%. There isn't much more advice I could give without seeing the code.

Joey

Posted 2010-03-13T23:06:37.803

Reputation: 36 381

19

Note for Windows users on 64-bit systems

Progra~1 = 'Program Files' Progra~2 = 'Program Files(x86)'

https://confluence.atlassian.com/display/DOC/Setting+the+JAVA_HOME+Variable+in+Windows

Robb

Posted 2010-03-13T23:06:37.803

Reputation: 191

1Very useful for getting rid of spaces in the $PATH environment variable when using MSYS on Windows. autoconf was not playing nice until I made this change. – Mike – 2014-05-03T20:58:52.873

13

There should either (a) not be any quotes in the MS-Windows PATH environmental variable (PATH command) or (b) there should be quotes surrounding the entire expression following the (SET command). Unfortunately, this is not very well documented by MS, although they do state that if quotes are used, they will be included in the value of the variable (Windows XP Command Line Reference).

$ SET BLAH="blah blah(1)"
$ ECHO %BLAH%
"blah blah(1)"
$ SET BLAH=blah blah(1)
$ ECHO %BLAH%
blah blah(1)

This can cause problems that are inconsistent and therefore difficult to diagnose. For example if your path includes "C:\Python27", your machine will say "'python' is not recognized as an internal or external command, operable program or batch file." when you try to execute python. However some libraries may still be available.

You do not need to "escape" spaces or parentheses. If you need to escape special characters, then put quotes around the entire expression, including the variable name.

SET "PATH=%PATH%;C:\Program Files (x86)\path with special characters"

or you can use parentheses too.

(SET VAR=can't contain ampersand, parentheses, pipe, gt or lt)

Note, double quotes must come in pairs.

(SET VAR=illegal characters!@#$%^*_-+={}[]\:;""',./?)
echo %VAR%
illegal characters!@#$%*_-+={}[]\:;""',./?

However, there probably are not any characters that are valid pathnames, that would cause a problem with the SET command.

Mark Mikofski

Posted 2010-03-13T23:06:37.803

Reputation: 558

1Did you try advised (SET PATH=%PATH%;C:\Program Files (x86)\path with special characters)? It's totally wrong! – JosefZ – 2015-11-07T07:40:17.460

@JosefZ - nice catch! My example has parentheses in it, and %PATH% could also have parentheses, which would cause (SET PYTHONPATH=C:\Program Files (x86) to be executed separately and then raise the error, \path with special characters) was not expected. But it does work for expressions that don't have parentheses. Thanks for the correction, I have updated my answer. – Mark Mikofski – 2015-11-08T07:26:05.283

1You actually wrote MS-DOS when you meant MS-Windows, and your commands were for MS-Windows. The OP did ask about MS-Windows. So why you are calling it MS-DOS I don't know. Even your links said NT (That is - Windows. It used to be 9X and NT, now it's just NT). Windows and MS-DOS are two different operating systems. I've seen the windows command prompt mistakenly called DOS before, but even that is not as wrong as what you called it. – barlop – 2014-06-14T13:02:09.410

@barlop, of course you are correct. Thanks for the edits. Until Windows-95, Windows was an application built on top of DOS. You could start Windows by typing the win command in DOS. In fact prior to Windows-3.1, everything, like Zork and WordStar were DOS applications. Then starting with Windows-98, there was no DOS. But I think some old timers like me still refer to the CMD shell mistakenly as a DOS shell. Sorry for the confusion, and thanks again for clarifying the intent of my answer. – Mark Mikofski – 2014-06-16T07:01:00.513

@MarkMikofski Actually Windows 9X(95/98/ME) was arguably built on DOS too. You could for example edit some file(maybe msdos.sys) some option(s) like bootGUI=0 and stop windows loading http://www.tokyopc.org/newsletter/1996/08/msdosed.html Whether you could then load windows from there I don't know. And a Win9X boot disk is considered DOS. Old timers that know what they're talking about as you do, usually are the last people to make the mistake of calling the windows command prompt DOS. And are the first people to be most adamant that it is not DOS.

– barlop – 2014-06-16T07:12:08.843

Also I didn't use NT much but it was around pre 98 too and that maybe didn't boot from DOS. The big change between 98 and XP, is XP is part of the NT family, so regular folk started getting NT. And NT was probably not built on DOS, and not built on DOS from even before XP, and possibly from the start of NT. Though I didn't use NT till XP(which is NT 5.1). Windows 2000 was NT 5.0, so, prior to XP and very well respected and preferred by many over XP's fisher price look. I would guess Windows 2000 wasn't built on DOS either. – barlop – 2014-06-16T07:14:22.197

2

Microsoft documents the problem in "Error running command shell scripts that include parentheses".

The solution they suggest is to use delayed expansion.

SETLOCAL ENABLEDELAYEDEXPANSION
SET VAR=string containing ( and ) ...
IF "y" == "y" (
    ECHO !VAR! %VAR%
)
ENDLOCAL

For setting a path in an if block, rather than using SET PATH=, you should probably use the PATH command.

SET AddToPath=C:\Program Files (x86)\Whatever

SETLOCAL ENABLEDELAYEDEXPANSION
IF "%X%" == "%Y%" (
    ECHO Adding !AddToPath! to path !PATH!
    PATH !AddToPath!;!PATH!
)

For other variables, another solution may be to use quotes, but around the whole thing:

SET "MyVar=C:\Program Files (x86)\Whatever"

mivk

Posted 2010-03-13T23:06:37.803

Reputation: 2 270

1

Joey in his answer says

This can happen if there are unescaped parentheses in a line inside a "block" (which also uses parentheses for delimiting).

and that's true. If there are unescaped parentheses one should, well escape them. That's what I did; I replaced

set PATH=some_path;%PATH%

with

set PATH="some_path;%PATH%"

and this solved the problem.

Piotr Dobrogost

Posted 2010-03-13T23:06:37.803

Reputation: 4 413

2Nope. You should use set "PATH=some_path;%PATH%" – JosefZ – 2015-11-07T07:34:55.040

1

I've experienced something similar. Microsoft explains the issue here: http://support.microsoft.com/kb/329308

Basically, instead of changing the Path variable via System->Adv Settings->Env Vars->System->PATH, try

My Computer->Manage->Computer Management (local)-> Properties-> Advanced-> Environment variables-> Settings

phearce

Posted 2010-03-13T23:06:37.803

Reputation: 41

1

In Windows 8 I've found very little success with any of these methods. Parentheses do not work, quotes work, but the "path" you modify this way isn't the path that gets used for locating executables, instead cmd still seems to be using the system path it inherited when you opened the window.

example: after determining the processor architecture, I want to add a couple of paths to the PATH environment variable. Actually, even just adding them temporarily would work since I only need them while a batch file is running. But that doesn't even work.

echo %path% displays the system PATH at the time the cmd was launched.

set path="%path%;%programfiles(x86)%\company\program\subdir" works but now %path% contains everything surrounded by quotes, and if I try to run a program in subdir from somewhere else, it fails. Using parentheses around the whole thing instead of quotes does not work.

Another thing I've noticed is that the same command will work if entered interactively in cmd, but not if encountered in a batch file. That's frightening. Yet another oddity is the intermittent loss of the last character of an environment variable's value! Another inconsistency is with third party programs: some can handle a %var% as a parameter, others don't.

Pete

Posted 2010-03-13T23:06:37.803

Reputation: 11

1

I had huge trouble making the following work in Win8 till I added double-quotes arround the value I was setting to fromFile variable. With out that, when fromFile contained a filename with parentheses, the next line that was trying to do string substitution to generate the toFile variable was failing. Note that I do use delayed expansion there to evaluate the variable at execution time instead of at parsing time (of the respective CALL instance)

::-- BATCH file that creates an *_576_5.* file from an *_640_t.* one (copying it)
::-- Author: George Birbilis (http://zoomicon.com)
::-- Credits: String replacement based on http://www.dostips.com/DtTipsStringManipulation.php

@ECHO OFF

::-- Loop for all files recursively --::

FOR /R %%f in (*_640_t.*) DO CALL :process %%f

ECHO(
PAUSE

GOTO :EOF

::-- Per-file actions --::

:process

:: Display progress...
::ECHO Processing %*
<nul (set/p dummy=.)

SETLOCAL ENABLEDELAYEDEXPANSION
SET fromFile="%*"
SET toFile=!fromFile:_640_t=_576_t!

IF NOT EXIST %toFile% CALL :generate %fromFile% %toFile%

GOTO :EOF

::-- Generate missing file --::

:generate

ECHO(
ECHO COPY %*
COPY %*

::PAUSE

GOTO :EOF

George Birbilis

Posted 2010-03-13T23:06:37.803

Reputation: 123