Windows.bat file,% ~ $ PATH: 1 quote

I have who.bat on Windows 7,

@echo off REM This bat searches a file in PATH list to see whether a file can be found. REM If found, it shows the file full path. REM which.bat gcc.exe REM shows REM gcc.exe is found: D:\GMU\MinGW2\bin\gcc.exe REM REM Note: Filename extension is significant in the search. Eg If you run REM which.bat gcc REM gcc.exe will not be matched. IF "%1" == "" goto END IF "%~$PATH:1" == "" ( echo %1 is not found in any directories from PATH env-var. ) ELSE ( echo %1 is found: %~$PATH:1 ) :END 

This bat works well until I find strange behavior today.

There is a file O:\temp\pfiles (x86)\mystuff.txt , and PATH has the content:

 PATH=O:\temp\pfiles (x86);D:\CmdUtils 

Running which mystuff.txt , I got the output of VERY STRANGE :

 \mystuff.txt was unexpected at this time. 

enter image description here

After some searching, I found that the name (x86) in the directory was causing the problem. To get a workaround, I have to add quotes to echo , for example:

 echo %1 is found: "%~$PATH:1" 

The disadvantage of this setting is obvious: quotation marks are printed on the screen, which is not always desirable in the opinion of the programmer.

Can someone explain this weird behavior?

I find this problem because in my real env I have several paths, such as C:\Program Files (x86)\Common Files\NetSarang in PATH, which exhibit exactly the same symptom.

enter image description here

+6
source share
3 answers

MS Dos is a fairly simple shell implementation, and since I realized that interpreting a single DOS command line goes through 2 steps:

  • evaluation of variables in the current row
  • interpretation of the evaluated command line

In this case, your command line is:

 IF "%~$PATH:1" == "" ( echo %1 is not found in any directories from PATH env-var. ) ELSE ( echo %1 is found: %~$PATH:1 ) 

will be interpreted as:

 IF "O:\temp\pfiles (x86)\mystuff.txt" == "" ( echo mystuff is not found in any directories from PATH env-var. ) ELSE ( echo mystuff.txt is found: O:\temp\pfiles (x86)\mystuff.txt ) 

Now we can notice the problem in (x86) , that is, the interpreter sees it something like this: first ) closes the else statement:

 ) ELSE ( echo mystuff.txt is found: O:\temp\pfiles (x86 )\mystuff.txt ) 

Solution: put "around" all potentially problematic variables.

I usually put quotes around the entire contents of the echo command, for example:

 echo "%1 is found: %~$PATH:1" 
+8
source

As it now becomes clear (from Michael Barr and Robert Lujo), I am trying to show a solution.

You need quotes, but you do not want to display them.

With expansion delay, the closing bracket is harmless

 setlocal EnableDelayedExpansion IF "%~$PATH:1" == "" ( echo %1 is not found in any directories from PATH env-var. ) ELSE ( set "found=%~$PATH:1" echo %1 is found: !found! ) 

Or just with a disappearing quote

 IF "%~$PATH:1" == "" ( echo %1 is not found in any directories from PATH env-var. ) ELSE ( for %%^" in ("") do ( echo %1 is found: %%~"%~$PATH:1 ) ) 
+4
source

I can guess the explanation (although not very useful): cmd.exe parser is not very smart - it gets confused with parens in %~$PATH:1 - when it expands the variable and sees the character ) , it assumes this closure for strings ) ELSE ( . (I think that it does nothing with the character ( in the extension, because they are significant only at the beginning of the command).

You can work around the problem by making sure that the extension that may contain ')' is not inside the command group (...) or that it is quoted (as you found). Since you don't need quotes, another workaround might look like this:

 @echo off REM This bat searches a file in PATH list to see whether a file can be found. REM If found, it shows the file full path. REM which.bat gcc.exe REM shows REM gcc.exe is found: D:\GMU\MinGW2\bin\gcc.exe REM REM Note: Filename extension is significant in the search. Eg If you run REM which.bat gcc REM gcc.exe will not be matched. IF "%1" == "" goto END IF "%~$PATH:1" == "" ( echo %1 is not found in any directories from PATH env-var. ) ELSE ( call :printfound %1 ) goto END :printfound echo %1 is found: %~$PATH:1 goto :eof :END 

This is ugly, but this is what you need to do with cmd.exe scripts.

+2
source

Source: https://habr.com/ru/post/944856/


All Articles