%0
引用参数 0 – 批处理文件的名称 – 始终与命令行或另一个批处理文件中指定的完全相同。
所以如果一个批处理文件名为Test.bat
存储在C:\Temp
例如从命令提示符窗口中启动,当前目录为C:\
执行temp\test
, then %0
被替换为temp\test
执行批处理文件时。
But %~f0
几乎总是被带有文件扩展名和完整路径的批处理文件名(完全限定的文件名)替换,并且始终不带双引号,即使文件名或路径包含一个或多个字符,例如空格或&()[]{}^=;!'+,`~
通常需要使用双引号。
因此批处理文件Test.bat
存储在C:\Temp
与线条
@echo %0
@echo %~f0
从命令提示符窗口中启动"temp\test.bat"
当前目录是C:\
输出:
"temp\test.bat"
C:\Temp\Test.bat
在这里可以看到所有的差异:
- 完全限定的批处理文件名,
- 始终没有双引号和
- 所有字母的大小写正确。
的描述%~f0
和其他修饰符可以在命令的帮助中读取CALL运行时输出call /?
或在指挥的帮助下FOR跑步时for /?
在命令提示符窗口中并阅读所有显示的页面。
Note 1:
如果稍后需要在批处理文件中使用,则应将完全限定的批处理文件名分配给环境变量,并且使用以下任一方法从批处理文件中修改当前目录CD or PUSHD。原因请参阅上的答案%~dp0 引用的批处理文件路径有时会在更改目录时发生变化,是什么原因? https://stackoverflow.com/questions/12141482/
Note 2:
运行上面的示例批处理文件C:\
只是与"temp\test"
输出结果:
"temp\test"
C:\Temp\Test
文件扩展名丢失是由于cmd
第一个注释的引用主题中描述的错误。启动批处理文件temp\test
不带双引号会产生预期的输出:
temp\test
C:\Temp\Test.bat
The 最终解决方案要获得始终确定且输出正确的批处理文件的完全限定文件名,请执行以下操作:
@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions DisableDelayedExpansion
echo %0
call :GetFullBatchFileName FullBatchFileName
setlocal EnableDelayedExpansion & echo !FullBatchFileName!& endlocal
endlocal
此代码甚至适用于批处理文件C:\Temp\Development & !Test!(!)\BestCode.bat
被处决于C:\
with "temp\development & !test!(!)\bestcode"
产生输出:
"temp\development & !test!(!)\bestcode"
C:\Temp\Development & !Test!(!)\BestCode.bat
为什么要使用延迟扩展来输出完整的批处理文件名?
分配给环境变量的文件/文件夹名称的输出,例如FullBatchFileName
用命令ECHO没有周围的"
需要使用延迟扩张 https://ss64.com/nt/delayedexpansion.html否则文件/文件夹名称中的&符号将被解释为无条件AND运算符而不是作为要输出的文件/文件夹名称的一部分的文字字符ECHO.
有关在分配给环境变量而没有包围的文件/文件夹名称的输出上不使用延迟扩展时可能发生的情况的示例"
:
@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions DisableDelayedExpansion
echo %0
call :GetFullBatchFileName FullBatchFileName
echo %FullBatchFileName%
endlocal
该批处理文件代码存储在C:\Temp\Development & !Test!(!)\NotGood1.bat
执行结果来自C:\
with "temp\development & !test!(!)\notgood1"
在输出中:
"temp\development & !test!(!)\notgood1"
C:\Temp\Development
'!Test!' is not recognized as an internal or external command,
operable program or batch file.
所以 Windows 命令处理器cmd
解释&
在环境变量的值中FullBatchFileName
作为无条件命令运算符AND。是因为ECHO仅输出完全限定批处理文件名的部分&
其余的解释为cmd.exe
作为执行命令后执行的第二个命令ECHO. cmd.exe
在这种情况下,会进行大量文件系统访问以查找可执行文件或脚本文件,这可能意味着!Test!(!)\NotGood1.bat
最后在找不到合适的东西后输出错误消息。
为什么一开始就没有开启延迟扩容?
不能从一开始就启用延迟扩展,因为这会导致解释!
在文件/文件夹名称字符串中作为延迟扩展变量引用的开头/结尾,如以下代码所示:
@echo off
goto Main
:GetFullBatchFileName
set "%1=%~f0" & goto :EOF
:Main
setlocal EnableExtensions EnableDelayedExpansion
set "Test="
echo %0
call :GetFullBatchFileName FullBatchFileName
echo !FullBatchFileName!
endlocal
该批处理文件代码存储在C:\Temp\Development & !Test!(!)\NotGood2.bat
执行结果来自C:\
with "temp\development & !test!(!)\notgood2"
在输出中:
"temp\development & ()\notgood2"
C:\Temp\Development & ()\NotGood2.bat
可见!test!
and !Test!
第三个!
圆括号中的内容从两个输出字符串中消失,因为!test!
and !Test!
被解释为延迟扩展变量引用并且没有环境变量Test
。第三!
被删除,解释为没有匹配的延迟扩展变量引用的开始!
标记变量名的结尾。
也可以看看:
- Windows 命令解释器 (CMD.EXE) 如何解析脚本? https://stackoverflow.com/questions/4094699/
- 使用 Windows 批处理文件的单行多个命令 https://stackoverflow.com/a/25344009/3074564
- GOTO :EOF 返回到哪里? https://stackoverflow.com/a/37518000/3074564