我在 Windows 10 Enterprise x64 上。我有以下目录层次结构,最内层有一个 BAT 文件:
C:\
dir\
my files\
run.bat
该 BAT 文件包含以下行:
@pushd %~dp0
@echo %~dp0
@popd
(含义和用法%~dp0
在帮助主题中有解释for /?
和这个答案)
如果我从当前目录为的命令提示符运行 BAT 文件C:\dir\my files
,那么我会得到一个非常合理的结果:
C:\dir\my files>run.bat
C:\dir\my files\
但是如果我从父目录调用它C:\dir
,我会得到:
C:\dir>"my files"\run.bat
C:\dir\my files\my files"\
"\
嗯?请注意,最内层的目录名称重复了,并且末尾有一些零散的字符。让我们以不同的方式尝试一下:
C:\dir>"my files\run.bat"
C:\dir\my files\my files\
杂散字符消失了,但目录名称仍然重复。这该如何解释?如何修改 BAT 文件,以便无论从哪个目录调用它,它都会给出相同的输出?
当然,我的真实场景比这个简化版本更复杂。 的值%~dp0
与其他字符串连接,分配给环境变量,作为参数传递给其他脚本等。
答案1
这是一个cmd.exe 中已知的错误/设计缺陷-%~dp0
如果引用了批处理脚本的路径,则变体可能会给出错误的结果。
有一个解决方法。您可以可靠地从 CALLed 子程序中获取值(请注意,必须使用至少一个修饰符~d
,如~f
等,否则您将获得子程序:label
)
@echo off
setlocal
pushd %~dp0
echo From main fails: "%~dp0"
call :test
popd
exit /b
:test
echo From subroutine OK: "%~dp0"
-- 示例输出 --
d:\dir>"my files\test.bat"
From main fails: "d:\dir\my files\my files\"
From subroutine OK: "d:\dir\my files\"
答案2
作为一种解决方法,请预先存储目录:
set "dir=%~dp0"
这是因为%0
实际上是被调用的路径(如argv
参数 0),所以在您的示例中它是"my files"\run.bat
或"my files\run.bat"
。
当你这样做%~dp0
,cmd.exe正在构建完整路径相对于当前目录然后提取您要求的部分。
在您之后pushd
,“完整路径” ( %~f0
) 将是:
C:\dir\my files\my files\run.bat
C:\dir\my files\my files"\run.bat
...然后修剪文件名以获取结果。