0

I'm running a batch file which updates some variables, notably %PATH%. My environment has a known bug where on of the directories in %PATH% is quoted, i.e.

PATH=c:\windows;...;"c:\program files\foo"\bin;c:\program files\...

I have a script which appends to PATH. When I do it inside an IF block, I get an error, e.g:

IF "1"=="1" (
  SET "PATH=%PATH%;c:\foo"
)

Gives the error

\Microsoft was unexpected at this time.

Where \Microsoft is obviously a fragment from one of the directories in %PATH%.

I don't get the error if the SET is not within a conditional block. Why is this?

Edit: It seems that this has more to do with the fact that PATH also contains parenthesis. Here's a better example of the issue:

C:\temp>SET "FOO=C:\Program Files (x86)\;foo"
C:\temp>ECHO %FOO%
C:\Program Files (x86)\;foo
C:\temp>IF "1"=="1" ( ECHO %FOO% )
\ was unexpected at this time.
C:\temp>IF "1"=="1"  ECHO %FOO%
C:\Program Files (x86)\;foo

So my question is really, why does it break if it's in the paren-delimited block?

Jimmy
  • 27,142
  • 5
  • 87
  • 100

4 Answers4

2

JosefZ properly identified the problem with ) in the path, but his suggested solution of removing all quotes is not safe.

Any path within the PATH variable may include ;, !, &, ) and/or ^, all of which can cause various issues when using normal %PATH% expansion.

There may be some paths with & or ) etc. quoted, as well as some unquoted paths with problem characters, so both %PATH% and "%PATH%" can fail.

The only guaranteed safe way to expand PATH is via delayed expansion, but you want the new value to survive the ENDLOCAL. What to do? . . .
. . . FOR /F and delayed expansion toggling to the rescue :-)

if "1"=="1" (
  setlocal enableDelayedExpansion
  for /f "eol=: delims=" %%P in ("!path!") do (
    endlocal
    set "path=%%P;c:\foo"
  )
)

Simplistic implementation of PATH extension via code like set path=%path%;c:\foo,
or set "path=%path%;c:\foo" is rampant, but it is not safe. By and large, people do not realize the subtle complexities involved with PATH management.

If you are ever trying to modify the PATH variable in a batch script that can be released into the wild, then you should always use a safe method like the one I have shown above.

The problem becomes even more complex if you want to conditionally append a path to PATH if and only if path is not already there. See How to check if directory exists in %PATH%? for a list of potential issues, as well as a fairly robust solution.

Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
0
SET "PATH=%PATH:"=%;c:\foo"

should fix the problem, since the quoes are irrelevant

Caution: This may not be true if a path-entry contains ";". In that case, you should rename the directory to something sensible.

Magoo
  • 77,302
  • 8
  • 62
  • 84
0

Just remove the outer quotes in your setting of the path variable. They're not required, by any means. Certainly not in this instance, where you have quotes being used internally within those quotes. The quotes should be inside your path variable, not outside the whole thing.

SET PATH=%PATH%;c:\foo

To further how it should be done, here's some additional examples to clarify...

SET PATH=%PATH%;C:\foo
SET PATH=%PATH%;"C:\Some Folder With Spaces In It"
SET PATH=%PATH%;"C:\Program Files\Foobar Inc Software"

But never...

SET "PATH=%PATH%;SomePath"
ManoDestra
  • 6,325
  • 6
  • 26
  • 50
  • Keep using `set "varName=varValue"` syntax pattern with double quotes (general escape rule); use quoted `"%varName%"` (or delayed expansion `!varName!` in some circumstances) if `varValue` contains characters that require escaping… – JosefZ Mar 16 '16 at 21:17
  • Exactly. If something contains quotes within it, then you don't use quotes outside it. – ManoDestra Mar 16 '16 at 21:24
  • But you are not in control of what is within PATH. There may be a combination of values with as well as values without quotes. – dbenham Mar 17 '16 at 02:55
  • Correct. Which is why you don't quote outside it when you're setting values to it. – ManoDestra Mar 17 '16 at 14:16
  • 2
    I think you missed my point. Sometimes `%PATH%` will fail, sometimes `"%PATH%"` will fail, and sometimes both will fail. See [my answer](http://stackoverflow.com/a/36050970/1012053). – dbenham Mar 17 '16 at 15:10
  • Yes, depends on what's already in it, but assuming that path is already in the valid format with various values having quotes or not, then you should be appending to it without external quotes. If it's not already in the correct format, then there's not a great deal you can do, except fix the path variable from scratch, but that doesn't invalidate how you should normally append to %PATH%. – ManoDestra Mar 17 '16 at 15:21
  • Good luck getting Microsoft, and all the millions of Windows users to begin quoting all paths within PATH, because that is the only way your proposed "solution" can work. But there is no need for such drastic measures. My answer provides a simple solution that is always safe. – dbenham Mar 17 '16 at 15:57
  • It's quite simple. If a path requires quotes, then it is appended with quotes. If it does not, then you can append it with quotes or not. It doesn't really matter in that instance. But the %PATH% variable can have paths appended to it that have quotes or do not. So, you should never encapsulate the WHOLE thing with quotes `"path=%path%;somepath"`. Not sure what part of this isn't making sense? If someone else puts a broken path in your path variable, then that's a separate issue that requires fixing, but they CAN append a properly quoted path to the %path% variable. No problem here at all :) – ManoDestra Mar 17 '16 at 16:11
  • In my situation, your examples with the quotes were actually the cause of the problem. Because I had a %PATH% value that contained both parenthesis and quotes, I couldn't use "%PATH%" because the quotes contained inside of it were interpreted as closing the opening quote before %PATH%. – Jimmy Mar 20 '16 at 00:29
0

You are right that this has more to do with the fact that PATH also contains parentheses. Next example shows the issue unambiguously:

==> ( set "varName=var"value(s) with"space(s) and"right parentheses"" )
with"space(s) and"right was unexpected at this time.

==> ( set varName=var"value(s) with"space(s) and"right parentheses" )
and"right parentheses" was unexpected at this time.

==>

Read answers to How does the Windows Command Interpreter (CMD.EXE) parse scripts? for explanation.

I can see the only solution: correct (adjust) your path variable once for always by removing all " double quotes as follows (check user variable path as well if present). Restart required.

adjust path variable

Community
  • 1
  • 1
JosefZ
  • 28,460
  • 5
  • 44
  • 83
  • Blindly removing all quotes from PATH is not safe because a semicolon `;` is a valid character in a path, and it is also the path delimiter. So any path that contains `;` must be quoted within variable PATH. – dbenham Mar 17 '16 at 00:54