命令行解释器cmd.exe在获取批处理文件路径的代码中存在错误,如果批处理文件是用双引号调用的,并且路径相对于当前工作目录。
创建一个目录C:\Temp\TestDir。在此目录中创建一个名为PathTest.bat的文件,并将以下代码复制并粘贴到此批处理文件中:
@echo off
set "StartIn=%CD%"
set "BatchPath=%~dp0"
echo Batch path before changing working directory is: %~dp0
cd ..
echo Batch path after changing working directory is: %~dp0
echo Saved path after changing working directory is: %BatchPath%
cd "%StartIn%"
echo Batch path after restoring working directory is: %~dp0
接下来打开命令提示符窗口并使用以下命令将工作目录设置为C:\Temp\TestDir:
cd /D C:\Temp\TestDir
现在通过以下方式调用Test.bat :
PathTest
PathTest.bat
.\PathTest
.\PathTest.bat
..\TestDir\PathTest
..\TestDir\PathTest.bat
\Temp\TestDir\PathTest
\Temp\TestDir\PathTest.bat
C:\Temp\TestDir\PathTest
C:\Temp\TestDir\PathTest.bat
对于所有 10 个测试用例,输出是C:\Temp\TestDir\的四倍。
测试用例 7 和 8 以相对于当前驱动器根目录的路径启动批处理文件。
现在让我们看看执行与以前相同的结果,但在批处理文件名周围使用双引号。
"PathTest"
"PathTest.bat"
".\PathTest"
".\PathTest.bat"
"..\TestDir\PathTest"
"..\TestDir\PathTest.bat"
"\Temp\TestDir\PathTest"
"\Temp\TestDir\PathTest.bat"
"C:\Temp\TestDir\PathTest"
"C:\Temp\TestDir\PathTest.bat"
对于测试用例 5 到 10,输出是C:\Temp\TestDir\的四倍。
但是对于测试用例 1 到 4,第二个输出行只是C:\Temp\而不是C:\Temp\TestDir\。
现在使用cd ..
将工作目录更改为C:\Temp并运行PathTest.bat,如下所示:
"TestDir\PathTest.bat"
".\TestDir\PathTest.bat"
"\Temp\TestDir\PathTest.bat"
"C:\Temp\TestDir\PathTest.bat"
测试用例 1 和 2 的第二个输出结果是C:\TestDir\,它根本不存在。
启动不带双引号的批处理文件会为所有 4 个测试用例生成正确的输出。
这清楚地表明该行为是由错误引起的。
每当批处理文件以双引号启动并且在启动时具有相对于当前工作目录%~dp0
的路径时,在批处理执行期间更改当前工作目录时获取批处理文件的路径是不可靠的。
这个 bug 也会根据Windows shell bug with how %~dp0 is resolved报告给 Microsoft 。
可以通过在更改工作目录之前将批处理文件的路径立即分配给环境变量来解决此错误,如上面的代码所示。
然后在需要批处理文件路径的地方引用此变量的值,并在需要时使用双引号。像这样%BatchPath%
的东西总是更好的可读性%~dp0
。
另一种解决方法是在使用双引号时始终使用完整路径(和文件扩展名)启动批处理文件,就像类Process
一样。