How does one check if a directory is already present in the PATH environment variable? Here's a start. All I've managed to do with the code below, though, is echo the first directory in %PATH%. Since this is a FOR loop you'd think it would enumerate all the directories in %PATH%, but it only gets the first one.
如何检查路径环境变量中的目录是否已经存在?这是一个开始。尽管如此,我所处理的所有代码都与%PATH%中的第一个目录相呼应。由于这是一个FOR循环,您可能会认为它会枚举%PATH%中的所有目录,但它只会得到第一个目录。
Is there a better way of doing this? Something like find or findstr operating on the %PATH% variable? I'd just like to check if a directory exists in the list of directories in %PATH%, to avoid adding something that might already be there.
有没有更好的办法?像在%PATH%变量上运行的find或findstr之类的东西?我只是想检查目录中是否存在%PATH%的目录,以避免添加可能已经存在的目录。
FOR /F "delims=;" %%P IN ("%PATH%") DO (
@ECHO %%~P
)
21 个解决方案
#1
83
First I will point out a number of issues that make this problem difficult to solve perfectly. Then I will present the most bullet-proof solution I have been able to come up with.
首先,我将指出一些使这个问题难以完美解决的问题。然后我将提出我所能想到的最防弹的解决方案。
For this discussion I will use lower case path to represent a single folder path in the file system, and upper case PATH to represent the PATH environment variable.
对于这个讨论,我将使用小写路径来表示文件系统中的单个文件夹路径,以及表示路径环境变量的大写路径。
From a practical standpoint, most people want to know if PATH contains the logical equivalent of a given path, not whether PATH contains an exact string match of a given path. This can be problematic because:
从实际的角度来看,大多数人想知道路径是否包含给定路径的逻辑等效项,而不是路径是否包含给定路径的精确字符串匹配。这可能会有问题,因为:
-
The trailing
\
is optional in a path
Most paths work equally well both with and without the trailing\
. The path logically points to the same location either way. The PATH frequently has a mixture of paths both with and without the trailing\
. This is probably the most common practical issue when searching a PATH for a match.在一条路径中,尾随\是可选的,大多数路径都可以同时使用和没有拖尾。路径逻辑上指向相同的位置。这条路经常有一个混合的路径,有和没有后面的\。在搜索匹配路径时,这可能是最常见的实际问题。
- There is one exception: The relative path
C:
(meaning the current working directory of drive C) is very different thanC:\
(meaning the root directory of drive C)
- 有一个例外:相对路径C:(表示驱动器C的当前工作目录)与C:\(即驱动器C的根目录)非常不同
- There is one exception: The relative path
-
Some paths have alternate short names
Any path that does not meet the old 8.3 standard has an alternate short form that does meet the standard. This is another PATH issue that I have seen with some frequency, particularly in business settings.有些路径有替代的短名称,任何不符合老8.3标准的路径都有符合标准的备选短格式。这是另一个我看到过的路径问题,特别是在业务设置中。
-
Windows accepts both
/
and\
as folder separators within a path.
This is not seen very often, but a path can be specified using/
instead of\
and it will function just fine within PATH (as well as in many other Windows contexts)Windows在路径中接受/和\作为文件夹分隔符。这不是经常看到的,但是可以使用/而不是\来指定路径,它将在path(以及其他许多Windows环境中)运行良好
-
Windows treats consecutive folder separators as one logical separator.
C:\FOLDER\\ and C:\FOLDER\ are equivalent. This actually helps in many contexts when dealing with a path because a developer can generally append\
to a path without bothering to check if the trailing\
already exists. But this obviously can cause problems if trying to perform an exact string match.Windows将连续的文件夹分隔符视为一个逻辑分隔符。C:\ \\ \\ \\ \\ \\ \\ \\ \等。在处理路径时,这实际上帮助了许多上下文,因为开发人员通常可以在不检查尾随\是否存在的情况下,将其附加到路径上。但是,如果试图执行精确的字符串匹配,这显然会导致问题。
- Exceptions: Not only is
C:
, different thanC:\
, butC:\
(a valid path), is different thanC:\\
(an invalid path).
- 例外:不仅是C:,不同于C:\,但是C:\(一条有效路径),与C:\\(无效路径)不同。
- Exceptions: Not only is
-
Windows trims trailing dots and spaces from file and directory names.
"C:\test. "
is equivalent to"C:\test"
.从文件和目录名称中拖出点和空格。“C:\测试。相当于“C:\test”。
-
The current
.\
and parent..\
folder specifiers may appear within a path
Unlikely to be seen in real life, but something likeC:\.\parent\child\..\.\child\
is equivalent toC:\parent\child
当前的。\和父母。在现实生活中不太可能出现的情况下,文件夹的说明符可能出现在一个不太可能出现的路径中,但像C:\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \。\儿童\等于C:\家长\儿童。
-
A path can optionally be enclosed within double quotes.
A path is often enclosed in quotes to protect against special characters like<space>
,
;
^
&
=
. Actually any number of quotes can appear before, within, and/or after the path. They are ignored by Windows except for the purpose of protecting against special characters. The quotes are never required within PATH unless a path contains a;
, but the quotes may be present never-the-less.一条路径可以选择性地包含在双引号内。路径通常包含在引号中,以保护特殊字符,比如
,;^ & =。实际上,任何数量的引号都可以在路径之前、内部和/或之后出现。除了保护特殊字符之外,它们被窗口忽略。除非路径包含a,否则在PATH中不需要引号;但是引号可能存在。 -
A path may be fully qualified or relative.
A fully qualified path points to exactly one specific location within the file system. A relative path location changes depending on the value of current working volumes and directories. There are three primary flavors of relative paths:一条路径可以是完全限定的或相对的。完全限定路径指向文件系统中的特定位置。相对路径位置的变化取决于当前工作卷和目录的值。相对路径有三种主要的味道:
-
D:
is relative to the current working directory of volume D: - D:相对于目前的工作目录D:
-
\myPath
is relative to the current working volume (could be C:, D: etc.) - \myPath相对于当前的工作卷(可以是C:, D:等等)
-
myPath
is relative to the current working volume and directory - myPath是相对于当前工作卷和目录的。
It is perfectly legal to include a relative path within PATH. This is very common in the Unix world because Unix does not search the current directory by default, so a Unix PATH will often contain
.\
. But Windows does search the current directory by default, so relative paths are rare in a Windows PATH.在路径中包含相对路径是完全合法的。这在Unix世界中很常见,因为Unix没有默认搜索当前目录,所以Unix路径通常包含。但是Windows默认搜索当前目录,所以相对路径在Windows路径中是很少见的。
-
So in order to reliably check if PATH already contains a path, we need a way to convert any given path into a canonical (standard) form. The ~s
modifier used by FOR variable and argument expansion is a simple method that addresses issues 1 - 6, and partially addresses issue 7. The ~s
modifier removes enclosing quotes, but preserves internal quotes. Issue 7 can be fully resolved by explicitly removing quotes from all paths prior to comparison. Note that if a path does not physically exist then the ~s
modifier will not append the \
to the path, nor will it convert the path into a valid 8.3 format.
因此,为了可靠地检查路径是否已经包含路径,我们需要一种方法将任何给定路径转换为规范(标准)形式。变量和参数扩展使用的~s修饰符是一个简单的方法,它解决了问题1 - 6,并部分地解决了问题7。“~s”修饰符删除包含引号,但保留内部引号。问题7可以通过在比较之前显式删除所有路径的引用来完全解决。请注意,如果路径没有物理上的存在,那么~s修饰符不会将\添加到路径中,也不会将路径转换为有效的8.3格式。
The problem with ~s
is it converts relative paths into fully qualified paths. This is problematic for Issue 8 because a relative path should never match a fully qualified path. We can use FINDSTR regular expressions to classify a path as either fully qualified or relative. A normal fully qualified path must start with <letter>:<separator>
but not <letter>:<separator><separator>
, where <separator> is either \
or /
. UNC paths are always fully qualified and must start with \\
. When comparing fully qualified paths we use the ~s
modifier. When comparing relative paths we use the raw strings. Finally, we never compare a fully qualified path to a relative path. This strategy provides a good practical solution for Issue 8. The only limitation is two logically equivalent relative paths could be treated as not matching, but this is a minor concern because relative paths are rare in a Windows PATH.
s的问题是它将相对路径转换为完全限定路径。这对于问题8来说是有问题的,因为相对路径不应该与完全限定的路径匹配。我们可以使用FINDSTR正则表达式将路径分类为完全限定的或相对的。一个正常的完全限定路径必须以 <字母> : <分隔的> ,但不是 <字母> : <分隔的> <分离器> ,其中 <分离器> 为\或/。UNC路径始终是完全合格的,必须以\\开始。当比较完全限定的路径时,我们使用~s修饰符。在比较相对路径时,我们使用原始字符串。最后,我们从不将完全限定的路径与相对路径进行比较。这个策略为第8期提供了一个很好的实践解决方案。唯一的限制是两个逻辑上等价的相对路径可以被视为不匹配,但这是一个次要的问题,因为相对路径在Windows路径中是很少见的。
There are some additional issues that complicate this problem:
还有一些问题使这个问题复杂化:
9) Normal expansion is not reliable when dealing with a PATH that contains special characters.
Special characters do not need to be quoted within PATH, but they could be. So a PATH like C:\THIS & THAT;"C:\& THE OTHER THING"
is perfectly valid, but it cannot be expanded safely using simple expansion because both "%PATH%"
and %PATH%
will fail.
9)在处理包含特殊字符的路径时,正常扩展不可靠。特殊字符不需要在路径中引用,但它们可以是。像C这样的路径;“C:\&另一件事”是完全有效的,但是不能使用简单的扩展来安全地扩展它,因为“%PATH%”和%PATH%将会失败。
10) The path delimiter is also valid within a path name
A ;
is used to delimit paths within PATH, but ;
can also be a valid character within a path, in which case the path must be quoted. This causes a parsing issue.
10)路径分隔符在路径名a中也是有效的;用于在路径中分隔路径,但是;也可以是路径中的一个有效字符,在这种情况下,路径必须被引用。这会导致解析问题。
jeb solved both issues 9 and 10 at 'Pretty print' windows %PATH% variable - how to split on ';' in CMD shell
jeb在“漂亮的打印”windows %PATH%变量上解决了9和10两个问题——如何在CMD shell中拆分。
So we can combine the ~s
modifier and path classification techniques along with my variation of jeb's PATH parser to get this nearly bullet proof solution for checking if a given path already exists within PATH. The function can be included and called from within a batch file, or it can stand alone and be called as its own inPath.bat batch file. It looks like a lot of code, but over half of it is comments.
因此,我们可以将~s修饰符和路径分类技术和我的jeb路径解析器的变体结合起来,以获得这个几乎是防弹的解决方案,以检查在路径中是否已经存在给定的路径。可以在批处理文件中包含和调用该函数,或者它可以独立存在,并被称为它自己的inPath。bat批处理文件。它看起来像很多代码,但超过一半是注释。
@echo off
:inPath pathVar
::
:: Tests if the path stored within variable pathVar exists within PATH.
::
:: The result is returned as the ERRORLEVEL:
:: 0 if the pathVar path is found in PATH.
:: 1 if the pathVar path is not found in PATH.
:: 2 if pathVar is missing or undefined or if PATH is undefined.
::
:: If the pathVar path is fully qualified, then it is logically compared
:: to each fully qualified path within PATH. The path strings don't have
:: to match exactly, they just need to be logically equivalent.
::
:: If the pathVar path is relative, then it is strictly compared to each
:: relative path within PATH. Case differences and double quotes are
:: ignored, but otherwise the path strings must match exactly.
::
::------------------------------------------------------------------------
::
:: Error checking
if "%~1"=="" exit /b 2
if not defined %~1 exit /b 2
if not defined path exit /b 2
::
:: Prepare to safely parse PATH into individual paths
setlocal DisableDelayedExpansion
set "var=%path:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"
set "var=%var:;=^;^;%"
set var=%var:""="%
set "var=%var:"=""Q%"
set "var=%var:;;="S"S%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
setlocal EnableDelayedExpansion
set "var=!var:"Q=!"
set "var=!var:"S"S=";"!"
::
:: Remove quotes from pathVar and abort if it becomes empty
set "new=!%~1:"=!"
if not defined new exit /b 2
::
:: Determine if pathVar is fully qualified
echo("!new!"|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& set "abs=1" || set "abs=0"
::
:: For each path in PATH, check if path is fully qualified and then do
:: proper comparison with pathVar.
:: Exit with ERRORLEVEL 0 if a match is found.
:: Delayed expansion must be disabled when expanding FOR variables
:: just in case the value contains !
for %%A in ("!new!\") do for %%B in ("!var!") do (
if "!!"=="" endlocal
for %%C in ("%%~B\") do (
echo(%%B|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& (if %abs%==1 if /i "%%~sA"=="%%~sC" exit /b 0) ^
|| (if %abs%==0 if /i "%%~A"=="%%~C" exit /b 0)
)
)
:: No match was found so exit with ERRORLEVEL 1
exit /b 1
The function can be used like so (assuming the batch file is named inPath.bat):
可以这样使用该函数(假设批处理文件名为inPath.bat):
set test=c:\mypath
call inPath test && (echo found) || (echo not found)
Typically the reason for checking if a path exists within PATH is because you want to append the path if it isn't there. This is normally done simply by using something like
path %path%;%newPath%
. But Issue 9 demonstrates how this is not reliable.
Another issue is how to return the final PATH value across the ENDLOCAL barrier at the end of the function, especially if the function could be called with delayed expansion enabled or disabled. Any unescaped !
will corrupt the value if delayed expansion is enabled.
另一个问题是如何在函数的末尾返回最终的路径值,尤其是在启用或禁用了延迟扩展的情况下。任何未逃跑的!如果启用延迟扩展,将损坏该值。
These problems are resolved using an amazing safe return technique that jeb invented here: http://www.dostips.com/forum/viewtopic.php?p=6930#p6930
这些问题的解决使用了jeb在这里发明的一种惊人的安全返回技术:http://www.dotess.com/forum/viewtopic.php?
@echo off
:addPath pathVar /B
::
:: Safely appends the path contained within variable pathVar to the end
:: of PATH if and only if the path does not already exist within PATH.
::
:: If the case insensitive /B option is specified, then the path is
:: inserted into the front (Beginning) of PATH instead.
::
:: If the pathVar path is fully qualified, then it is logically compared
:: to each fully qualified path within PATH. The path strings are
:: considered a match if they are logically equivalent.
::
:: If the pathVar path is relative, then it is strictly compared to each
:: relative path within PATH. Case differences and double quotes are
:: ignored, but otherwise the path strings must match exactly.
::
:: Before appending the pathVar path, all double quotes are stripped, and
:: then the path is enclosed in double quotes if and only if the path
:: contains at least one semicolon.
::
:: addPath aborts with ERRORLEVEL 2 if pathVar is missing or undefined
:: or if PATH is undefined.
::
::------------------------------------------------------------------------
::
:: Error checking
if "%~1"=="" exit /b 2
if not defined %~1 exit /b 2
if not defined path exit /b 2
::
:: Determine if function was called while delayed expansion was enabled
setlocal
set "NotDelayed=!"
::
:: Prepare to safely parse PATH into individual paths
setlocal DisableDelayedExpansion
set "var=%path:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"
set "var=%var:;=^;^;%"
set var=%var:""="%
set "var=%var:"=""Q%"
set "var=%var:;;="S"S%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
setlocal EnableDelayedExpansion
set "var=!var:"Q=!"
set "var=!var:"S"S=";"!"
::
:: Remove quotes from pathVar and abort if it becomes empty
set "new=!%~1:"^=!"
if not defined new exit /b 2
::
:: Determine if pathVar is fully qualified
echo("!new!"|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& set "abs=1" || set "abs=0"
::
:: For each path in PATH, check if path is fully qualified and then
:: do proper comparison with pathVar. Exit if a match is found.
:: Delayed expansion must be disabled when expanding FOR variables
:: just in case the value contains !
for %%A in ("!new!\") do for %%B in ("!var!") do (
if "!!"=="" setlocal disableDelayedExpansion
for %%C in ("%%~B\") do (
echo(%%B|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& (if %abs%==1 if /i "%%~sA"=="%%~sC" exit /b 0) ^
|| (if %abs%==0 if /i %%A==%%C exit /b 0)
)
)
::
:: Build the modified PATH, enclosing the added path in quotes
:: only if it contains ;
setlocal enableDelayedExpansion
if "!new:;=!" neq "!new!" set new="!new!"
if /i "%~2"=="/B" (set "rtn=!new!;!path!") else set "rtn=!path!;!new!"
::
:: rtn now contains the modified PATH. We need to safely pass the
:: value accross the ENDLOCAL barrier
::
:: Make rtn safe for assignment using normal expansion by replacing
:: % and " with not yet defined FOR variables
set "rtn=!rtn:%%=%%A!"
set "rtn=!rtn:"=%%B!"
::
:: Escape ^ and ! if function was called while delayed expansion was enabled.
:: The trailing ! in the second assignment is critical and must not be removed.
if not defined NotDelayed set "rtn=!rtn:^=^^^^!"
if not defined NotDelayed set "rtn=%rtn:!=^^^!%" !
::
:: Pass the rtn value accross the ENDLOCAL barrier using FOR variables to
:: restore the % and " characters. Again the trailing ! is critical.
for /f "usebackq tokens=1,2" %%A in ('%%^ ^"') do (
endlocal & endlocal & endlocal & endlocal & endlocal
set "path=%rtn%" !
)
exit /b 0
#2
34
I haven't done any batch file programming in a while, but:
我在一段时间内没有做过任何批处理文件编程,但是:
echo ;%PATH%; | find /C /I ";<string>;"
should give you 0 if string is not found and 1 or more if it is.
如果没有找到字符串,应该给你0,如果是1或更多。
EDIT: Added case-insensitive flag, thanks to Panos.
编辑:添加不区分大小写的标志,感谢Panos。
#3
19
Another way to check if something is in the path is to execute some innocent executable that is not going to fail if it's there, and check the result. As an example, next code snippet checks if maven is in the path:
另一种检查路径的方法是执行一些无害的可执行文件,如果它在那里,它不会失败,并检查结果。例如,下一个代码片段检查maven是否在路径中:
mvn --help > NUL 2> NUL
if errorlevel 1 goto mvnNotInPath
So I try to run mvn --help, ignore the output (don't actually want to see the help if maven is there)( > NUL), and also don't display the error message if maven was not found (2> NUL).
因此,我尝试运行mvn——帮助,忽略输出(如果maven在那里,实际上不希望看到帮助)(> NUL),而且如果maven没有找到,也不要显示错误消息(2> NUL)。
#4
7
After reading the answers here I think I can provide a new point of view: if the purpose of this question is to know if the path to a certain executable file exists in %PATH%
and if not, insert it (and this is the only reason to do that, I think), then it may solved in a slightly different way: "How to check if the directory of a certain executable program exist in %PATH%"? This question may be easily solved this way:
在阅读的答案我想我可以提供一个新的观点:如果这个问题的目的是知道某个可执行文件的路径存在于%路径%如果没有,插入(这是唯一的原因,我认为),那么它可能解决一个稍微不同的方式:“如何检查如果某个可执行程序的目录存在于% %”?这个问题很容易解决:
for %%p in (programname.exe) do set "progpath=%%~$PATH:p"
if not defined progpath (
rem The path to programname.exe don't exist in PATH variable, insert it:
set "PATH=%PATH%;C:\path\to\progranname"
)
If you don't know the extension of the executable file, just review all of them:
如果您不知道可执行文件的扩展名,请查看所有这些文件:
set "progpath="
for %%e in (%PATHEXT%) do (
if not defined progpath (
for %%p in (programname.%%e) do set "progpath=%%~$PATH:p"
)
)
#5
6
Using for
and delims
, you cannot capture an arbitrary number of fields (as Adam pointed out as well) so you have to use a looping technique instead. The following command script will list each path in the PATH
environment variable on a separate line:
使用for和delims,您不能捕获任意数量的字段(正如Adam指出的那样),因此您必须使用循环技术。下面的命令脚本将在一个单独的行中列出path环境变量中的每个路径:
@echo off
setlocal
if "%~1"=="" (
set PATHQ=%PATH%
) else (
set PATHQ=%~1 )
:WHILE
if "%PATHQ%"=="" goto WEND
for /F "delims=;" %%i in ("%PATHQ%") do echo %%i
for /F "delims=; tokens=1,*" %%i in ("%PATHQ%") do set PATHQ=%%j
goto WHILE
:WEND
It simulates a classical while…wend construct found in many programming languages. With this in place, you can use something like findstr
to subsequently filter and look for a particular path. For example, if you saved the above script in a file called tidypath.cmd
then here is how you could pipe to findstr
, looking for paths under the standard programs directory (using a case-insensitive match):
它模拟了一个经典的while…wend构造在许多编程语言中。有了这个,您就可以使用像findstr这样的东西来过滤和查找特定的路径。例如,如果您在一个名为tidypath的文件中保存了上面的脚本。然后,这里是如何向findstr发送管道,查找标准程序目录下的路径(使用不区分大小写的匹配):
> tidypath | findstr /i "%ProgramFiles%"
#6
4
This will look for an exact but case-insensitive match, so mind any trailing backslashes etc.:
这将寻找一种精确但不区分大小写的匹配,所以要注意任何后面的反斜杠等。
for %P in ("%path:;=";"%") do @if /i %P=="PATH_TO_CHECK" echo %P exists in PATH
or, in a batch file (e.g. checkpath.bat) which takes an argument:
或者,在一个批处理文件中(例如checkpath.bat),它采用了一个参数:
@for %%P in ("%path:;=";"%") do @if /i %%P=="%~1" echo %%P exists in PATH
In the latter form, one could call e.g. checkpath "%ProgramFiles%"
to see if the specified path already exists in PATH.
在后面的表单中,可以调用checkpath“%ProgramFiles%”来查看指定的路径是否已经在path中存在。
Please note that this implementation assumes no semicolons or quotes are present inside a single path item.
请注意,此实现假定在单个路径项中没有分号或引号。
#7
2
I took your implementation using the for loop and extended it into something that iterates through all elements of the path. Each iteration of the for loop removes the first element of the path (%p) from the entire path (held in %q and %r).
我使用for循环来实现您的实现,并将其扩展到遍历路径的所有元素。for循环的每个迭代从整个路径(% q和%r)中删除路径的第一个元素(%p)。
@echo off
SET MYPATHCOPY=%PATH%
:search
for /f "delims=; tokens=1,2*" %%p in ("%MYPATHCOPY%") do (
@echo %%~p
SET MYPATHCOPY=%%~q;%%~r
)
if "%MYPATHCOPY%"==";" goto done;
goto search;
:done
Sample output:
样例输出:
Z:\>path.bat
C:\Program Files\Microsoft DirectX SDK (November 2007)\Utilities\Bin\x86
c:\program files\imagemagick-6.3.4-q16
C:\WINDOWS\system32
C:\WINDOWS
C:\SFU\common\
c:\Program Files\Debugging Tools for Windows
C:\Program Files\Nmap
#8
2
Add Directory to PATH if not already exists:
添加目录到路径,如果还不存在的话:
set myPath=c:\mypath
For /F "Delims=" %%I In ('echo %PATH% ^| find /C /I "%myPath%"') Do set pathExists=%%I 2>Nul
If %pathExists%==0 (set PATH=%myPath%;%PATH%)
#9
2
You can also use substring replacement to test for the presence of a substring. Here I remove quotes to create PATH_NQ, then I remove "c:\mydir" from the PATH_NQ and compare it to the original to see if anything changed:
您还可以使用子字符串替换来测试是否存在子字符串。在这里,我删除了创建PATH_NQ的引号,然后从PATH_NQ中删除了“c:\mydir”,并将其与原始代码进行比较,以查看是否有任何更改:
set PATH_NQ=%PATH:"=%
if not "%PATH_NQ%"=="%PATH_NQ:c:\mydir=%" goto already_in_path
set PATH=%PATH%;c:\mydir
:already_in_path
#10
2
I've combined some of the above answers to come up with this to ensure that a given path entry exists exactly as given with as much brevity as possible and no junk echos on the command line.
我将上面的一些答案结合起来,以确保给定的路径条目能够尽可能简洁地存在,并且在命令行上没有垃圾回声。
set myPath=<pathToEnsure | %1>
echo ;%PATH%; | find /C /I ";%myPath%;" >nul
if %ERRORLEVEL% NEQ 0 set PATH=%PATH%;%myPath%
#11
2
If your question was "why doesn't this cmd script fragment work?" then the answer is that for /f
iterates over lines. The delims
split lines into fields, but you're only capturing the first field in %%P
. There is no way to capture an arbitrary number of fields with a for /f
loop.
如果您的问题是“为什么这个cmd脚本片段不工作?”那么答案就是for /f迭代了行。delims将代码分割成字段,但是您只捕获了%%P中的第一个字段。没有办法用for /f循环捕获任意数量的字段。
#12
1
Building on rcar's answer, you have to make sure a substring of the target isn't found.
在rcar的答案上,您必须确保没有找到目标的子字符串。
if a%X%==a%PATH% echo %X% is in PATH
echo %PATH% | find /c /i ";%X%"
if errorlevel 1 echo %X% is in PATH
echo %PATH% | find /c /i "%X%;"
if errorlevel 1 echo %X% is in PATH
#13
1
You mention that you want to avoid adding the directory to search path if it already exists there. Is your intention to store the directory permanently to the path, or just temporarily for batch file's sake?
您提到,如果它已经存在,您希望避免将该目录添加到搜索路径中。您的意图是将目录永久存储到路径中,还是只是暂时存储批文件?
If you wish to add (or remove) directories permanently to PATH, take a look at Path Manager (pathman.exe) utility in Windows Resource Kit Tools for administrative tasks, http://support.microsoft.com/kb/927229. With that you can add or remove components of both system and user paths, and it will handle anomalies such as duplicate entries.
如果您希望永久地添加(或删除)目录,请查看Windows资源工具包中的PATH Manager (pathman.exe)实用工具,用于管理任务,http://support.microsoft.com/kb/927229。通过这样,您可以添加或删除系统和用户路径的组件,它将处理诸如重复项之类的异常。
If you need to modify the path only temporarily for a batch file, I would just add the extra path in front of the path, with the risk of slight performance hit because of duplicate entry in the path.
如果您只需要临时修改一个批处理文件的路径,那么我只需要在路径前面添加额外的路径,因为路径中有重复的条目,可能会造成轻微的性能损失。
#14
1
This version works fairly well. It simply checks whether vim71 is in the path, and prepends it if not.
这个版本运行得相当好。它只是检查vim71是否在路径中,如果没有的话,它会预先检查。
@echo off
echo %PATH% | find /c /i "vim71" > nul
if not errorlevel 1 goto jump
PATH = C:\Program Files\Vim\vim71\;%PATH%
:jump
This demo is to illustrate the errorlevel logic:
这个演示是为了演示errorlevel逻辑:
@echo on
echo %PATH% | find /c /i "Windows"
if "%errorlevel%"=="0" echo Found Windows
echo %PATH% | find /c /i "Nonesuch"
if "%errorlevel%"=="0" echo Found Nonesuch
The logic is reversed in the vim71 code since errorlevel 1 is equivalent to errorlevel >= 1. It follows that errorlevel 0 would always evaluate true, so "not errorlevel 1
" is used.
在vim71代码中,逻辑是反向的,因为errorlevel 1相当于errorlevel >= 1。它遵循的是errorlevel 0始终是正确的,因此使用“not errorlevel 1”。
Postscript Checking may not be necessary if you use setlocal and endlocal to localise your environment settings, e.g.
如果您使用setlocal和endlocal来本地化您的环境设置,那么Postscript检查可能是不必要的。
@echo off
setlocal
PATH = C:\Program Files\Vim\vim71\;%PATH%
rem your code here
endlocal
After endlocal you are back with your original path.
结束后,你回到你原来的路径。
#15
1
A comment to the "addPath" script; When supplying a path with spaces, it throws up.
对“addPath”脚本的注释;当提供一个带有空格的路径时,它会抛出。
Example: call addPath "c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin"
示例:调用addPath“c:\程序文件(x86)\Microsoft SDKs\Windows\v7.0A\Bin”
yields: 'Files' is not recognized as an internal or external command, operable program or batch file.
生成:“文件”不被识别为内部或外部命令、可操作程序或批处理文件。
#16
1
In general this is to put an exe/dll on the path. As long as this file wont appear anywhere else:
一般来说,这是在路径上放一个exe/dll。只要该文件不出现在其他地方:
@echo off
where /q <put filename here>
if %errorlevel% == 1 (
setx PATH "%PATH%;<additional path stuff>"
) else (
echo "already set path"
)
#17
1
This is a variation to Kevin Edwards's answer using string replacement. The basic pattern is:
这是对凯文·爱德华兹的回答使用字符串替换的一个变体。基本模式是:
IF "%PATH:new_path=%" == "%PATH%" PATH=%PATH%;new_path
For example:
例如:
IF "%PATH:C:\Scripts=%" == "%PATH%" PATH=%PATH%;C:\Scripts
In a nutshell, we make a conditional test where we attempt to remove/replace new_path
from our PATH
environment variable. If new_path
doesn't exist the condition succeeds and the new_path
will be appended to PATH
for the first time. If new_path
already exists then the condition fails and we will not add new_path
a second time.
简单地说,我们做了一个条件测试,尝试从PATH环境变量中移除/替换new_path。如果new_path不存在,条件成功,new_path将会被追加到第一次路径中。如果new_path已经存在,那么条件就会失败,我们将不会第二次添加new_path。
#18
1
You can accomplish this using PoweShell;
你可以用PoweShell来完成这个任务;
Test-Path $ENV:SystemRoot\YourDirectory
Test-Path C:\Windows\YourDirectory
This returns TRUE
or FALSE
这个返回TRUE或FALSE。
Short, simle and easy!
短,微笑和简单!
#19
1
Just as an alternative:
只是作为一种替代方法:
-
In the folder you are going to search the
PATH
variable for, create a temporary file with such an unusual name that you would never ever expect any other file on your computer to have.在您要搜索PATH变量的文件夹中,创建一个临时文件,该文件具有这样一个不寻常的名称,您将永远不会期望您的计算机上有任何其他文件。
-
Use the standard batch scripting construct that lets you perform the search for a file by looking up a directory list defined by some environment variable (typically
PATH
).使用标准批处理脚本构造,通过查找某个环境变量(通常是路径)定义的目录列表来执行搜索文件。
-
Check if the result of the search matches the path in question, and display the outcome.
检查搜索结果是否与问题路径匹配,并显示结果。
-
Delete the temporary file.
删除临时文件。
This might look like this:
这可能是这样的:
@ECHO OFF
SET "mypath=D:\the\searched-for\path"
SET unusualname=nowthisissupposedtobesomeveryunusualfilename
ECHO.>"%mypath%\%unusualname%"
FOR %%f IN (%unusualname%) DO SET "foundpath=%%~dp$PATH:f"
ERASE "%mypath%\%unusualname%"
IF "%mypath%" == "%foundpath%" (
ECHO The dir exists in PATH
) ELSE (
ECHO The dir DOES NOT exist in PATH
)
Known issues:
已知问题:
-
The method can work only if the directory exists (which isn't always the case).
该方法只能在目录存在的情况下工作(并不总是这样)。
-
Creating / deleting files in a directory affects its 'modified date/time' attribute (which may be an undesirable effect sometimes).
在目录中创建/删除文件会影响其“修改日期/时间”属性(有时可能会产生不良影响)。
-
Making up a globally unique file name in one's mind cannot be considered very reliable. Generating such a name is itself not a trivial task.
在一个人的头脑中创建一个全局唯一的文件名不能被认为是非常可靠的。生成这样的名称本身并不是一项简单的任务。
#20
0
This routine will search for a path\ or file.ext in the path variable it returns 0 if found. Path\ or file may contain spaces if quoted. If a variable is passed as the last argument it will be set to d:\path\file
.
这个例程将搜索路径\或文件。在路径变量中,如果找到,它返回0。如果引用的话,路径\或文件可能包含空格。如果将一个变量作为最后一个参数传递,它将被设置为d:\path\file。
@echo off&goto :PathCheck
:PathCheck.CMD
echo.PathCheck.CMD: Checks for existence of a path or file in %%PATH%% variable
echo.Usage: PathCheck.CMD [Checkpath] or [Checkfile] [PathVar]
echo.Checkpath must have a trailing \ but checkfile must not
echo.If Checkpath contains spaces use quotes ie. "C:\Check path\"
echo.Checkfile must not include a path, just the filename.ext
echo.If Checkfile contains spaces use quotes ie. "Check File.ext"
echo.Returns 0 if found, 1 if not or -1 if checkpath does not exist at all
echo.If PathVar is not in command line it will be echoed with surrounding quotes
echo.If PathVar is passed it will be set to d:\path\checkfile with no trailing \
echo.Then %%PathVar%% will be set to the fully qualified path to Checkfile
echo.Note: %%PathVar%% variable set will not be surrounded with quotes
echo.To view the path listing line by line use: PathCheck.CMD /L
exit/b 1
:PathCheck
if "%~1"=="" goto :PathCheck.CMD
setlocal EnableDelayedExpansion
set "PathVar=%~2"
set "pth="
set "pcheck=%~1"
if "%pcheck:~-1%" equ "\" (
if not exist %pcheck% endlocal&exit/b -1
set/a pth=1
)
for %%G in ("%path:;=" "%") do (
set "Pathfd=%%~G\"
set "Pathfd=!Pathfd:\\=\!"
if /i "%pcheck%" equ "/L" echo.!Pathfd!
if defined pth (
if /i "%pcheck%" equ "!Pathfd!" endlocal&exit/b 0
) else (
if exist "!Pathfd!%pcheck%" goto :CheckfileFound
)
)
endlocal&exit/b 1
:CheckfileFound
endlocal&(
if not "%PathVar%"=="" (
call set "%~2=%Pathfd%%pcheck%"
) else (echo."%Pathfd%%pcheck%")
exit/b 0
)
#21
0
Just to elaborate on Heyvoon's (2015.06.08) response using Powershell, this simple Powershell script should give you detail on %path%
为了详细说明Heyvoon的(2015.06.08)使用Powershell的响应,这个简单的Powershell脚本应该在%path%上提供详细信息。
$env:Path -split ";" | % {"$(test-path $_);$_"}
generating this kind of output which you can independently verify
生成这样的输出,您可以独立验证。
True;C:\WINDOWS
True;C:\WINDOWS\system32
True;C:\WINDOWS\System32\Wbem
False;C:windows\System32\windowsPowerShell\v1.0\
False;C:\Program Files (x86)\Java\jre7\bin
to reassemble for updating Path:
重新装配更新路径:
$x=$null;foreach ($t in ($env:Path -split ";") ) {if (test-path $t) {$x+=$t+";"}};$x
#1
83
First I will point out a number of issues that make this problem difficult to solve perfectly. Then I will present the most bullet-proof solution I have been able to come up with.
首先,我将指出一些使这个问题难以完美解决的问题。然后我将提出我所能想到的最防弹的解决方案。
For this discussion I will use lower case path to represent a single folder path in the file system, and upper case PATH to represent the PATH environment variable.
对于这个讨论,我将使用小写路径来表示文件系统中的单个文件夹路径,以及表示路径环境变量的大写路径。
From a practical standpoint, most people want to know if PATH contains the logical equivalent of a given path, not whether PATH contains an exact string match of a given path. This can be problematic because:
从实际的角度来看,大多数人想知道路径是否包含给定路径的逻辑等效项,而不是路径是否包含给定路径的精确字符串匹配。这可能会有问题,因为:
-
The trailing
\
is optional in a path
Most paths work equally well both with and without the trailing\
. The path logically points to the same location either way. The PATH frequently has a mixture of paths both with and without the trailing\
. This is probably the most common practical issue when searching a PATH for a match.在一条路径中,尾随\是可选的,大多数路径都可以同时使用和没有拖尾。路径逻辑上指向相同的位置。这条路经常有一个混合的路径,有和没有后面的\。在搜索匹配路径时,这可能是最常见的实际问题。
- There is one exception: The relative path
C:
(meaning the current working directory of drive C) is very different thanC:\
(meaning the root directory of drive C)
- 有一个例外:相对路径C:(表示驱动器C的当前工作目录)与C:\(即驱动器C的根目录)非常不同
- There is one exception: The relative path
-
Some paths have alternate short names
Any path that does not meet the old 8.3 standard has an alternate short form that does meet the standard. This is another PATH issue that I have seen with some frequency, particularly in business settings.有些路径有替代的短名称,任何不符合老8.3标准的路径都有符合标准的备选短格式。这是另一个我看到过的路径问题,特别是在业务设置中。
-
Windows accepts both
/
and\
as folder separators within a path.
This is not seen very often, but a path can be specified using/
instead of\
and it will function just fine within PATH (as well as in many other Windows contexts)Windows在路径中接受/和\作为文件夹分隔符。这不是经常看到的,但是可以使用/而不是\来指定路径,它将在path(以及其他许多Windows环境中)运行良好
-
Windows treats consecutive folder separators as one logical separator.
C:\FOLDER\\ and C:\FOLDER\ are equivalent. This actually helps in many contexts when dealing with a path because a developer can generally append\
to a path without bothering to check if the trailing\
already exists. But this obviously can cause problems if trying to perform an exact string match.Windows将连续的文件夹分隔符视为一个逻辑分隔符。C:\ \\ \\ \\ \\ \\ \\ \\ \等。在处理路径时,这实际上帮助了许多上下文,因为开发人员通常可以在不检查尾随\是否存在的情况下,将其附加到路径上。但是,如果试图执行精确的字符串匹配,这显然会导致问题。
- Exceptions: Not only is
C:
, different thanC:\
, butC:\
(a valid path), is different thanC:\\
(an invalid path).
- 例外:不仅是C:,不同于C:\,但是C:\(一条有效路径),与C:\\(无效路径)不同。
- Exceptions: Not only is
-
Windows trims trailing dots and spaces from file and directory names.
"C:\test. "
is equivalent to"C:\test"
.从文件和目录名称中拖出点和空格。“C:\测试。相当于“C:\test”。
-
The current
.\
and parent..\
folder specifiers may appear within a path
Unlikely to be seen in real life, but something likeC:\.\parent\child\..\.\child\
is equivalent toC:\parent\child
当前的。\和父母。在现实生活中不太可能出现的情况下,文件夹的说明符可能出现在一个不太可能出现的路径中,但像C:\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \。\儿童\等于C:\家长\儿童。
-
A path can optionally be enclosed within double quotes.
A path is often enclosed in quotes to protect against special characters like<space>
,
;
^
&
=
. Actually any number of quotes can appear before, within, and/or after the path. They are ignored by Windows except for the purpose of protecting against special characters. The quotes are never required within PATH unless a path contains a;
, but the quotes may be present never-the-less.一条路径可以选择性地包含在双引号内。路径通常包含在引号中,以保护特殊字符,比如
,;^ & =。实际上,任何数量的引号都可以在路径之前、内部和/或之后出现。除了保护特殊字符之外,它们被窗口忽略。除非路径包含a,否则在PATH中不需要引号;但是引号可能存在。 -
A path may be fully qualified or relative.
A fully qualified path points to exactly one specific location within the file system. A relative path location changes depending on the value of current working volumes and directories. There are three primary flavors of relative paths:一条路径可以是完全限定的或相对的。完全限定路径指向文件系统中的特定位置。相对路径位置的变化取决于当前工作卷和目录的值。相对路径有三种主要的味道:
-
D:
is relative to the current working directory of volume D: - D:相对于目前的工作目录D:
-
\myPath
is relative to the current working volume (could be C:, D: etc.) - \myPath相对于当前的工作卷(可以是C:, D:等等)
-
myPath
is relative to the current working volume and directory - myPath是相对于当前工作卷和目录的。
It is perfectly legal to include a relative path within PATH. This is very common in the Unix world because Unix does not search the current directory by default, so a Unix PATH will often contain
.\
. But Windows does search the current directory by default, so relative paths are rare in a Windows PATH.在路径中包含相对路径是完全合法的。这在Unix世界中很常见,因为Unix没有默认搜索当前目录,所以Unix路径通常包含。但是Windows默认搜索当前目录,所以相对路径在Windows路径中是很少见的。
-
So in order to reliably check if PATH already contains a path, we need a way to convert any given path into a canonical (standard) form. The ~s
modifier used by FOR variable and argument expansion is a simple method that addresses issues 1 - 6, and partially addresses issue 7. The ~s
modifier removes enclosing quotes, but preserves internal quotes. Issue 7 can be fully resolved by explicitly removing quotes from all paths prior to comparison. Note that if a path does not physically exist then the ~s
modifier will not append the \
to the path, nor will it convert the path into a valid 8.3 format.
因此,为了可靠地检查路径是否已经包含路径,我们需要一种方法将任何给定路径转换为规范(标准)形式。变量和参数扩展使用的~s修饰符是一个简单的方法,它解决了问题1 - 6,并部分地解决了问题7。“~s”修饰符删除包含引号,但保留内部引号。问题7可以通过在比较之前显式删除所有路径的引用来完全解决。请注意,如果路径没有物理上的存在,那么~s修饰符不会将\添加到路径中,也不会将路径转换为有效的8.3格式。
The problem with ~s
is it converts relative paths into fully qualified paths. This is problematic for Issue 8 because a relative path should never match a fully qualified path. We can use FINDSTR regular expressions to classify a path as either fully qualified or relative. A normal fully qualified path must start with <letter>:<separator>
but not <letter>:<separator><separator>
, where <separator> is either \
or /
. UNC paths are always fully qualified and must start with \\
. When comparing fully qualified paths we use the ~s
modifier. When comparing relative paths we use the raw strings. Finally, we never compare a fully qualified path to a relative path. This strategy provides a good practical solution for Issue 8. The only limitation is two logically equivalent relative paths could be treated as not matching, but this is a minor concern because relative paths are rare in a Windows PATH.
s的问题是它将相对路径转换为完全限定路径。这对于问题8来说是有问题的,因为相对路径不应该与完全限定的路径匹配。我们可以使用FINDSTR正则表达式将路径分类为完全限定的或相对的。一个正常的完全限定路径必须以 <字母> : <分隔的> ,但不是 <字母> : <分隔的> <分离器> ,其中 <分离器> 为\或/。UNC路径始终是完全合格的,必须以\\开始。当比较完全限定的路径时,我们使用~s修饰符。在比较相对路径时,我们使用原始字符串。最后,我们从不将完全限定的路径与相对路径进行比较。这个策略为第8期提供了一个很好的实践解决方案。唯一的限制是两个逻辑上等价的相对路径可以被视为不匹配,但这是一个次要的问题,因为相对路径在Windows路径中是很少见的。
There are some additional issues that complicate this problem:
还有一些问题使这个问题复杂化:
9) Normal expansion is not reliable when dealing with a PATH that contains special characters.
Special characters do not need to be quoted within PATH, but they could be. So a PATH like C:\THIS & THAT;"C:\& THE OTHER THING"
is perfectly valid, but it cannot be expanded safely using simple expansion because both "%PATH%"
and %PATH%
will fail.
9)在处理包含特殊字符的路径时,正常扩展不可靠。特殊字符不需要在路径中引用,但它们可以是。像C这样的路径;“C:\&另一件事”是完全有效的,但是不能使用简单的扩展来安全地扩展它,因为“%PATH%”和%PATH%将会失败。
10) The path delimiter is also valid within a path name
A ;
is used to delimit paths within PATH, but ;
can also be a valid character within a path, in which case the path must be quoted. This causes a parsing issue.
10)路径分隔符在路径名a中也是有效的;用于在路径中分隔路径,但是;也可以是路径中的一个有效字符,在这种情况下,路径必须被引用。这会导致解析问题。
jeb solved both issues 9 and 10 at 'Pretty print' windows %PATH% variable - how to split on ';' in CMD shell
jeb在“漂亮的打印”windows %PATH%变量上解决了9和10两个问题——如何在CMD shell中拆分。
So we can combine the ~s
modifier and path classification techniques along with my variation of jeb's PATH parser to get this nearly bullet proof solution for checking if a given path already exists within PATH. The function can be included and called from within a batch file, or it can stand alone and be called as its own inPath.bat batch file. It looks like a lot of code, but over half of it is comments.
因此,我们可以将~s修饰符和路径分类技术和我的jeb路径解析器的变体结合起来,以获得这个几乎是防弹的解决方案,以检查在路径中是否已经存在给定的路径。可以在批处理文件中包含和调用该函数,或者它可以独立存在,并被称为它自己的inPath。bat批处理文件。它看起来像很多代码,但超过一半是注释。
@echo off
:inPath pathVar
::
:: Tests if the path stored within variable pathVar exists within PATH.
::
:: The result is returned as the ERRORLEVEL:
:: 0 if the pathVar path is found in PATH.
:: 1 if the pathVar path is not found in PATH.
:: 2 if pathVar is missing or undefined or if PATH is undefined.
::
:: If the pathVar path is fully qualified, then it is logically compared
:: to each fully qualified path within PATH. The path strings don't have
:: to match exactly, they just need to be logically equivalent.
::
:: If the pathVar path is relative, then it is strictly compared to each
:: relative path within PATH. Case differences and double quotes are
:: ignored, but otherwise the path strings must match exactly.
::
::------------------------------------------------------------------------
::
:: Error checking
if "%~1"=="" exit /b 2
if not defined %~1 exit /b 2
if not defined path exit /b 2
::
:: Prepare to safely parse PATH into individual paths
setlocal DisableDelayedExpansion
set "var=%path:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"
set "var=%var:;=^;^;%"
set var=%var:""="%
set "var=%var:"=""Q%"
set "var=%var:;;="S"S%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
setlocal EnableDelayedExpansion
set "var=!var:"Q=!"
set "var=!var:"S"S=";"!"
::
:: Remove quotes from pathVar and abort if it becomes empty
set "new=!%~1:"=!"
if not defined new exit /b 2
::
:: Determine if pathVar is fully qualified
echo("!new!"|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& set "abs=1" || set "abs=0"
::
:: For each path in PATH, check if path is fully qualified and then do
:: proper comparison with pathVar.
:: Exit with ERRORLEVEL 0 if a match is found.
:: Delayed expansion must be disabled when expanding FOR variables
:: just in case the value contains !
for %%A in ("!new!\") do for %%B in ("!var!") do (
if "!!"=="" endlocal
for %%C in ("%%~B\") do (
echo(%%B|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& (if %abs%==1 if /i "%%~sA"=="%%~sC" exit /b 0) ^
|| (if %abs%==0 if /i "%%~A"=="%%~C" exit /b 0)
)
)
:: No match was found so exit with ERRORLEVEL 1
exit /b 1
The function can be used like so (assuming the batch file is named inPath.bat):
可以这样使用该函数(假设批处理文件名为inPath.bat):
set test=c:\mypath
call inPath test && (echo found) || (echo not found)
Typically the reason for checking if a path exists within PATH is because you want to append the path if it isn't there. This is normally done simply by using something like
path %path%;%newPath%
. But Issue 9 demonstrates how this is not reliable.
Another issue is how to return the final PATH value across the ENDLOCAL barrier at the end of the function, especially if the function could be called with delayed expansion enabled or disabled. Any unescaped !
will corrupt the value if delayed expansion is enabled.
另一个问题是如何在函数的末尾返回最终的路径值,尤其是在启用或禁用了延迟扩展的情况下。任何未逃跑的!如果启用延迟扩展,将损坏该值。
These problems are resolved using an amazing safe return technique that jeb invented here: http://www.dostips.com/forum/viewtopic.php?p=6930#p6930
这些问题的解决使用了jeb在这里发明的一种惊人的安全返回技术:http://www.dotess.com/forum/viewtopic.php?
@echo off
:addPath pathVar /B
::
:: Safely appends the path contained within variable pathVar to the end
:: of PATH if and only if the path does not already exist within PATH.
::
:: If the case insensitive /B option is specified, then the path is
:: inserted into the front (Beginning) of PATH instead.
::
:: If the pathVar path is fully qualified, then it is logically compared
:: to each fully qualified path within PATH. The path strings are
:: considered a match if they are logically equivalent.
::
:: If the pathVar path is relative, then it is strictly compared to each
:: relative path within PATH. Case differences and double quotes are
:: ignored, but otherwise the path strings must match exactly.
::
:: Before appending the pathVar path, all double quotes are stripped, and
:: then the path is enclosed in double quotes if and only if the path
:: contains at least one semicolon.
::
:: addPath aborts with ERRORLEVEL 2 if pathVar is missing or undefined
:: or if PATH is undefined.
::
::------------------------------------------------------------------------
::
:: Error checking
if "%~1"=="" exit /b 2
if not defined %~1 exit /b 2
if not defined path exit /b 2
::
:: Determine if function was called while delayed expansion was enabled
setlocal
set "NotDelayed=!"
::
:: Prepare to safely parse PATH into individual paths
setlocal DisableDelayedExpansion
set "var=%path:"=""%"
set "var=%var:^=^^%"
set "var=%var:&=^&%"
set "var=%var:|=^|%"
set "var=%var:<=^<%"
set "var=%var:>=^>%"
set "var=%var:;=^;^;%"
set var=%var:""="%
set "var=%var:"=""Q%"
set "var=%var:;;="S"S%"
set "var=%var:^;^;=;%"
set "var=%var:""="%"
setlocal EnableDelayedExpansion
set "var=!var:"Q=!"
set "var=!var:"S"S=";"!"
::
:: Remove quotes from pathVar and abort if it becomes empty
set "new=!%~1:"^=!"
if not defined new exit /b 2
::
:: Determine if pathVar is fully qualified
echo("!new!"|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& set "abs=1" || set "abs=0"
::
:: For each path in PATH, check if path is fully qualified and then
:: do proper comparison with pathVar. Exit if a match is found.
:: Delayed expansion must be disabled when expanding FOR variables
:: just in case the value contains !
for %%A in ("!new!\") do for %%B in ("!var!") do (
if "!!"=="" setlocal disableDelayedExpansion
for %%C in ("%%~B\") do (
echo(%%B|findstr /i /r /c:^"^^\"[a-zA-Z]:[\\/][^\\/]" ^
/c:^"^^\"[\\][\\]" >nul ^
&& (if %abs%==1 if /i "%%~sA"=="%%~sC" exit /b 0) ^
|| (if %abs%==0 if /i %%A==%%C exit /b 0)
)
)
::
:: Build the modified PATH, enclosing the added path in quotes
:: only if it contains ;
setlocal enableDelayedExpansion
if "!new:;=!" neq "!new!" set new="!new!"
if /i "%~2"=="/B" (set "rtn=!new!;!path!") else set "rtn=!path!;!new!"
::
:: rtn now contains the modified PATH. We need to safely pass the
:: value accross the ENDLOCAL barrier
::
:: Make rtn safe for assignment using normal expansion by replacing
:: % and " with not yet defined FOR variables
set "rtn=!rtn:%%=%%A!"
set "rtn=!rtn:"=%%B!"
::
:: Escape ^ and ! if function was called while delayed expansion was enabled.
:: The trailing ! in the second assignment is critical and must not be removed.
if not defined NotDelayed set "rtn=!rtn:^=^^^^!"
if not defined NotDelayed set "rtn=%rtn:!=^^^!%" !
::
:: Pass the rtn value accross the ENDLOCAL barrier using FOR variables to
:: restore the % and " characters. Again the trailing ! is critical.
for /f "usebackq tokens=1,2" %%A in ('%%^ ^"') do (
endlocal & endlocal & endlocal & endlocal & endlocal
set "path=%rtn%" !
)
exit /b 0
#2
34
I haven't done any batch file programming in a while, but:
我在一段时间内没有做过任何批处理文件编程,但是:
echo ;%PATH%; | find /C /I ";<string>;"
should give you 0 if string is not found and 1 or more if it is.
如果没有找到字符串,应该给你0,如果是1或更多。
EDIT: Added case-insensitive flag, thanks to Panos.
编辑:添加不区分大小写的标志,感谢Panos。
#3
19
Another way to check if something is in the path is to execute some innocent executable that is not going to fail if it's there, and check the result. As an example, next code snippet checks if maven is in the path:
另一种检查路径的方法是执行一些无害的可执行文件,如果它在那里,它不会失败,并检查结果。例如,下一个代码片段检查maven是否在路径中:
mvn --help > NUL 2> NUL
if errorlevel 1 goto mvnNotInPath
So I try to run mvn --help, ignore the output (don't actually want to see the help if maven is there)( > NUL), and also don't display the error message if maven was not found (2> NUL).
因此,我尝试运行mvn——帮助,忽略输出(如果maven在那里,实际上不希望看到帮助)(> NUL),而且如果maven没有找到,也不要显示错误消息(2> NUL)。
#4
7
After reading the answers here I think I can provide a new point of view: if the purpose of this question is to know if the path to a certain executable file exists in %PATH%
and if not, insert it (and this is the only reason to do that, I think), then it may solved in a slightly different way: "How to check if the directory of a certain executable program exist in %PATH%"? This question may be easily solved this way:
在阅读的答案我想我可以提供一个新的观点:如果这个问题的目的是知道某个可执行文件的路径存在于%路径%如果没有,插入(这是唯一的原因,我认为),那么它可能解决一个稍微不同的方式:“如何检查如果某个可执行程序的目录存在于% %”?这个问题很容易解决:
for %%p in (programname.exe) do set "progpath=%%~$PATH:p"
if not defined progpath (
rem The path to programname.exe don't exist in PATH variable, insert it:
set "PATH=%PATH%;C:\path\to\progranname"
)
If you don't know the extension of the executable file, just review all of them:
如果您不知道可执行文件的扩展名,请查看所有这些文件:
set "progpath="
for %%e in (%PATHEXT%) do (
if not defined progpath (
for %%p in (programname.%%e) do set "progpath=%%~$PATH:p"
)
)
#5
6
Using for
and delims
, you cannot capture an arbitrary number of fields (as Adam pointed out as well) so you have to use a looping technique instead. The following command script will list each path in the PATH
environment variable on a separate line:
使用for和delims,您不能捕获任意数量的字段(正如Adam指出的那样),因此您必须使用循环技术。下面的命令脚本将在一个单独的行中列出path环境变量中的每个路径:
@echo off
setlocal
if "%~1"=="" (
set PATHQ=%PATH%
) else (
set PATHQ=%~1 )
:WHILE
if "%PATHQ%"=="" goto WEND
for /F "delims=;" %%i in ("%PATHQ%") do echo %%i
for /F "delims=; tokens=1,*" %%i in ("%PATHQ%") do set PATHQ=%%j
goto WHILE
:WEND
It simulates a classical while…wend construct found in many programming languages. With this in place, you can use something like findstr
to subsequently filter and look for a particular path. For example, if you saved the above script in a file called tidypath.cmd
then here is how you could pipe to findstr
, looking for paths under the standard programs directory (using a case-insensitive match):
它模拟了一个经典的while…wend构造在许多编程语言中。有了这个,您就可以使用像findstr这样的东西来过滤和查找特定的路径。例如,如果您在一个名为tidypath的文件中保存了上面的脚本。然后,这里是如何向findstr发送管道,查找标准程序目录下的路径(使用不区分大小写的匹配):
> tidypath | findstr /i "%ProgramFiles%"
#6
4
This will look for an exact but case-insensitive match, so mind any trailing backslashes etc.:
这将寻找一种精确但不区分大小写的匹配,所以要注意任何后面的反斜杠等。
for %P in ("%path:;=";"%") do @if /i %P=="PATH_TO_CHECK" echo %P exists in PATH
or, in a batch file (e.g. checkpath.bat) which takes an argument:
或者,在一个批处理文件中(例如checkpath.bat),它采用了一个参数:
@for %%P in ("%path:;=";"%") do @if /i %%P=="%~1" echo %%P exists in PATH
In the latter form, one could call e.g. checkpath "%ProgramFiles%"
to see if the specified path already exists in PATH.
在后面的表单中,可以调用checkpath“%ProgramFiles%”来查看指定的路径是否已经在path中存在。
Please note that this implementation assumes no semicolons or quotes are present inside a single path item.
请注意,此实现假定在单个路径项中没有分号或引号。
#7
2
I took your implementation using the for loop and extended it into something that iterates through all elements of the path. Each iteration of the for loop removes the first element of the path (%p) from the entire path (held in %q and %r).
我使用for循环来实现您的实现,并将其扩展到遍历路径的所有元素。for循环的每个迭代从整个路径(% q和%r)中删除路径的第一个元素(%p)。
@echo off
SET MYPATHCOPY=%PATH%
:search
for /f "delims=; tokens=1,2*" %%p in ("%MYPATHCOPY%") do (
@echo %%~p
SET MYPATHCOPY=%%~q;%%~r
)
if "%MYPATHCOPY%"==";" goto done;
goto search;
:done
Sample output:
样例输出:
Z:\>path.bat
C:\Program Files\Microsoft DirectX SDK (November 2007)\Utilities\Bin\x86
c:\program files\imagemagick-6.3.4-q16
C:\WINDOWS\system32
C:\WINDOWS
C:\SFU\common\
c:\Program Files\Debugging Tools for Windows
C:\Program Files\Nmap
#8
2
Add Directory to PATH if not already exists:
添加目录到路径,如果还不存在的话:
set myPath=c:\mypath
For /F "Delims=" %%I In ('echo %PATH% ^| find /C /I "%myPath%"') Do set pathExists=%%I 2>Nul
If %pathExists%==0 (set PATH=%myPath%;%PATH%)
#9
2
You can also use substring replacement to test for the presence of a substring. Here I remove quotes to create PATH_NQ, then I remove "c:\mydir" from the PATH_NQ and compare it to the original to see if anything changed:
您还可以使用子字符串替换来测试是否存在子字符串。在这里,我删除了创建PATH_NQ的引号,然后从PATH_NQ中删除了“c:\mydir”,并将其与原始代码进行比较,以查看是否有任何更改:
set PATH_NQ=%PATH:"=%
if not "%PATH_NQ%"=="%PATH_NQ:c:\mydir=%" goto already_in_path
set PATH=%PATH%;c:\mydir
:already_in_path
#10
2
I've combined some of the above answers to come up with this to ensure that a given path entry exists exactly as given with as much brevity as possible and no junk echos on the command line.
我将上面的一些答案结合起来,以确保给定的路径条目能够尽可能简洁地存在,并且在命令行上没有垃圾回声。
set myPath=<pathToEnsure | %1>
echo ;%PATH%; | find /C /I ";%myPath%;" >nul
if %ERRORLEVEL% NEQ 0 set PATH=%PATH%;%myPath%
#11
2
If your question was "why doesn't this cmd script fragment work?" then the answer is that for /f
iterates over lines. The delims
split lines into fields, but you're only capturing the first field in %%P
. There is no way to capture an arbitrary number of fields with a for /f
loop.
如果您的问题是“为什么这个cmd脚本片段不工作?”那么答案就是for /f迭代了行。delims将代码分割成字段,但是您只捕获了%%P中的第一个字段。没有办法用for /f循环捕获任意数量的字段。
#12
1
Building on rcar's answer, you have to make sure a substring of the target isn't found.
在rcar的答案上,您必须确保没有找到目标的子字符串。
if a%X%==a%PATH% echo %X% is in PATH
echo %PATH% | find /c /i ";%X%"
if errorlevel 1 echo %X% is in PATH
echo %PATH% | find /c /i "%X%;"
if errorlevel 1 echo %X% is in PATH
#13
1
You mention that you want to avoid adding the directory to search path if it already exists there. Is your intention to store the directory permanently to the path, or just temporarily for batch file's sake?
您提到,如果它已经存在,您希望避免将该目录添加到搜索路径中。您的意图是将目录永久存储到路径中,还是只是暂时存储批文件?
If you wish to add (or remove) directories permanently to PATH, take a look at Path Manager (pathman.exe) utility in Windows Resource Kit Tools for administrative tasks, http://support.microsoft.com/kb/927229. With that you can add or remove components of both system and user paths, and it will handle anomalies such as duplicate entries.
如果您希望永久地添加(或删除)目录,请查看Windows资源工具包中的PATH Manager (pathman.exe)实用工具,用于管理任务,http://support.microsoft.com/kb/927229。通过这样,您可以添加或删除系统和用户路径的组件,它将处理诸如重复项之类的异常。
If you need to modify the path only temporarily for a batch file, I would just add the extra path in front of the path, with the risk of slight performance hit because of duplicate entry in the path.
如果您只需要临时修改一个批处理文件的路径,那么我只需要在路径前面添加额外的路径,因为路径中有重复的条目,可能会造成轻微的性能损失。
#14
1
This version works fairly well. It simply checks whether vim71 is in the path, and prepends it if not.
这个版本运行得相当好。它只是检查vim71是否在路径中,如果没有的话,它会预先检查。
@echo off
echo %PATH% | find /c /i "vim71" > nul
if not errorlevel 1 goto jump
PATH = C:\Program Files\Vim\vim71\;%PATH%
:jump
This demo is to illustrate the errorlevel logic:
这个演示是为了演示errorlevel逻辑:
@echo on
echo %PATH% | find /c /i "Windows"
if "%errorlevel%"=="0" echo Found Windows
echo %PATH% | find /c /i "Nonesuch"
if "%errorlevel%"=="0" echo Found Nonesuch
The logic is reversed in the vim71 code since errorlevel 1 is equivalent to errorlevel >= 1. It follows that errorlevel 0 would always evaluate true, so "not errorlevel 1
" is used.
在vim71代码中,逻辑是反向的,因为errorlevel 1相当于errorlevel >= 1。它遵循的是errorlevel 0始终是正确的,因此使用“not errorlevel 1”。
Postscript Checking may not be necessary if you use setlocal and endlocal to localise your environment settings, e.g.
如果您使用setlocal和endlocal来本地化您的环境设置,那么Postscript检查可能是不必要的。
@echo off
setlocal
PATH = C:\Program Files\Vim\vim71\;%PATH%
rem your code here
endlocal
After endlocal you are back with your original path.
结束后,你回到你原来的路径。
#15
1
A comment to the "addPath" script; When supplying a path with spaces, it throws up.
对“addPath”脚本的注释;当提供一个带有空格的路径时,它会抛出。
Example: call addPath "c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin"
示例:调用addPath“c:\程序文件(x86)\Microsoft SDKs\Windows\v7.0A\Bin”
yields: 'Files' is not recognized as an internal or external command, operable program or batch file.
生成:“文件”不被识别为内部或外部命令、可操作程序或批处理文件。
#16
1
In general this is to put an exe/dll on the path. As long as this file wont appear anywhere else:
一般来说,这是在路径上放一个exe/dll。只要该文件不出现在其他地方:
@echo off
where /q <put filename here>
if %errorlevel% == 1 (
setx PATH "%PATH%;<additional path stuff>"
) else (
echo "already set path"
)
#17
1
This is a variation to Kevin Edwards's answer using string replacement. The basic pattern is:
这是对凯文·爱德华兹的回答使用字符串替换的一个变体。基本模式是:
IF "%PATH:new_path=%" == "%PATH%" PATH=%PATH%;new_path
For example:
例如:
IF "%PATH:C:\Scripts=%" == "%PATH%" PATH=%PATH%;C:\Scripts
In a nutshell, we make a conditional test where we attempt to remove/replace new_path
from our PATH
environment variable. If new_path
doesn't exist the condition succeeds and the new_path
will be appended to PATH
for the first time. If new_path
already exists then the condition fails and we will not add new_path
a second time.
简单地说,我们做了一个条件测试,尝试从PATH环境变量中移除/替换new_path。如果new_path不存在,条件成功,new_path将会被追加到第一次路径中。如果new_path已经存在,那么条件就会失败,我们将不会第二次添加new_path。
#18
1
You can accomplish this using PoweShell;
你可以用PoweShell来完成这个任务;
Test-Path $ENV:SystemRoot\YourDirectory
Test-Path C:\Windows\YourDirectory
This returns TRUE
or FALSE
这个返回TRUE或FALSE。
Short, simle and easy!
短,微笑和简单!
#19
1
Just as an alternative:
只是作为一种替代方法:
-
In the folder you are going to search the
PATH
variable for, create a temporary file with such an unusual name that you would never ever expect any other file on your computer to have.在您要搜索PATH变量的文件夹中,创建一个临时文件,该文件具有这样一个不寻常的名称,您将永远不会期望您的计算机上有任何其他文件。
-
Use the standard batch scripting construct that lets you perform the search for a file by looking up a directory list defined by some environment variable (typically
PATH
).使用标准批处理脚本构造,通过查找某个环境变量(通常是路径)定义的目录列表来执行搜索文件。
-
Check if the result of the search matches the path in question, and display the outcome.
检查搜索结果是否与问题路径匹配,并显示结果。
-
Delete the temporary file.
删除临时文件。
This might look like this:
这可能是这样的:
@ECHO OFF
SET "mypath=D:\the\searched-for\path"
SET unusualname=nowthisissupposedtobesomeveryunusualfilename
ECHO.>"%mypath%\%unusualname%"
FOR %%f IN (%unusualname%) DO SET "foundpath=%%~dp$PATH:f"
ERASE "%mypath%\%unusualname%"
IF "%mypath%" == "%foundpath%" (
ECHO The dir exists in PATH
) ELSE (
ECHO The dir DOES NOT exist in PATH
)
Known issues:
已知问题:
-
The method can work only if the directory exists (which isn't always the case).
该方法只能在目录存在的情况下工作(并不总是这样)。
-
Creating / deleting files in a directory affects its 'modified date/time' attribute (which may be an undesirable effect sometimes).
在目录中创建/删除文件会影响其“修改日期/时间”属性(有时可能会产生不良影响)。
-
Making up a globally unique file name in one's mind cannot be considered very reliable. Generating such a name is itself not a trivial task.
在一个人的头脑中创建一个全局唯一的文件名不能被认为是非常可靠的。生成这样的名称本身并不是一项简单的任务。
#20
0
This routine will search for a path\ or file.ext in the path variable it returns 0 if found. Path\ or file may contain spaces if quoted. If a variable is passed as the last argument it will be set to d:\path\file
.
这个例程将搜索路径\或文件。在路径变量中,如果找到,它返回0。如果引用的话,路径\或文件可能包含空格。如果将一个变量作为最后一个参数传递,它将被设置为d:\path\file。
@echo off&goto :PathCheck
:PathCheck.CMD
echo.PathCheck.CMD: Checks for existence of a path or file in %%PATH%% variable
echo.Usage: PathCheck.CMD [Checkpath] or [Checkfile] [PathVar]
echo.Checkpath must have a trailing \ but checkfile must not
echo.If Checkpath contains spaces use quotes ie. "C:\Check path\"
echo.Checkfile must not include a path, just the filename.ext
echo.If Checkfile contains spaces use quotes ie. "Check File.ext"
echo.Returns 0 if found, 1 if not or -1 if checkpath does not exist at all
echo.If PathVar is not in command line it will be echoed with surrounding quotes
echo.If PathVar is passed it will be set to d:\path\checkfile with no trailing \
echo.Then %%PathVar%% will be set to the fully qualified path to Checkfile
echo.Note: %%PathVar%% variable set will not be surrounded with quotes
echo.To view the path listing line by line use: PathCheck.CMD /L
exit/b 1
:PathCheck
if "%~1"=="" goto :PathCheck.CMD
setlocal EnableDelayedExpansion
set "PathVar=%~2"
set "pth="
set "pcheck=%~1"
if "%pcheck:~-1%" equ "\" (
if not exist %pcheck% endlocal&exit/b -1
set/a pth=1
)
for %%G in ("%path:;=" "%") do (
set "Pathfd=%%~G\"
set "Pathfd=!Pathfd:\\=\!"
if /i "%pcheck%" equ "/L" echo.!Pathfd!
if defined pth (
if /i "%pcheck%" equ "!Pathfd!" endlocal&exit/b 0
) else (
if exist "!Pathfd!%pcheck%" goto :CheckfileFound
)
)
endlocal&exit/b 1
:CheckfileFound
endlocal&(
if not "%PathVar%"=="" (
call set "%~2=%Pathfd%%pcheck%"
) else (echo."%Pathfd%%pcheck%")
exit/b 0
)
#21
0
Just to elaborate on Heyvoon's (2015.06.08) response using Powershell, this simple Powershell script should give you detail on %path%
为了详细说明Heyvoon的(2015.06.08)使用Powershell的响应,这个简单的Powershell脚本应该在%path%上提供详细信息。
$env:Path -split ";" | % {"$(test-path $_);$_"}
generating this kind of output which you can independently verify
生成这样的输出,您可以独立验证。
True;C:\WINDOWS
True;C:\WINDOWS\system32
True;C:\WINDOWS\System32\Wbem
False;C:windows\System32\windowsPowerShell\v1.0\
False;C:\Program Files (x86)\Java\jre7\bin
to reassemble for updating Path:
重新装配更新路径:
$x=$null;foreach ($t in ($env:Path -split ";") ) {if (test-path $t) {$x+=$t+";"}};$x