【问题标题】:Batch scripting: What's the difference between %0 and %~f0?批处理脚本:%0 和 %~f0 有什么区别?
【发布时间】:2016-06-11 16:13:05
【问题描述】:

我有一个批处理脚本,我想在其中获取脚本的完整路径。我很好奇,这有什么区别:

set scriptpath=%0

还有这个:

set scriptpath=%~f0

感谢您的帮助。

【问题讨论】:

  • 输入for /?阅读,或点击here

标签: windows batch-file cmd windows-10 command-prompt


【解决方案1】:

%0 引用参数 0 - 批处理文件的名称 - 始终与命令行或另一个批处理文件中指定的完全一致。

因此,如果一个名为Test.bat 的批处理文件存储在C:\Temp 中,例如从当前目录为C:\ 并执行temp\test 的命令提示符窗口中启动,那么%0 将被@ 替换987654332@ 执行批处理文件。

但是%~f0 几乎总是被带有文件扩展名和完整路径的批处理文件名——完全限定的文件名——并且总是不带双引号,即使文件名或路径包含一个或多个字符,如空格或&()[]{}^=;!'+,`~ 通常需要使用双引号。

因此批处理文件 Test.bat 存储在 C:\Temp 与行

@echo %0
@echo %~f0

从带有"temp\test.bat" 的命令提示符窗口中开始,当前目录为C:\ 输出:

"temp\test.bat"
C:\Temp\Test.bat

这里可以看出所有不同之处:

  • 完全限定的批处理文件名,
  • 总是不带双引号和
  • 所有字母大小写正确。

%~f0 和其他修饰符的描述可以在运行 call /? 的命令 CALL 输出的帮助或运行 @987654343 的命令 FOR 的帮助中读取@ 在命令提示符窗口中并读取所有显示的页面。

注 1:

如果稍后在批处理文件中需要,应将完全限定的批处理文件名分配给环境变量,并使用 CDPUSHD 从批处理文件中修改当前目录强>。原因见What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory?上的答案

注2:

C:\ 运行上面的示例批处理文件,仅使用"temp\test" 导致输出:

"temp\test"
C:\Temp\Test

缺少文件扩展名,这是由第一个注释的引用主题中描述的cmd 错误引起的。使用不带双引号的 temp\test 启动批处理文件会产生预期的输出:

temp\test
C:\Temp\Test.bat

获得始终确定并正确输出的批处理文件的完全限定文件名的最终解决方案是:

@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:\ 执行的批处理文件C:\Temp\Development & !Test!(!)\BestCode.bat"temp\development & !test!(!)\bestcode" 产生输出:

"temp\development & !test!(!)\bestcode"
C:\Temp\Development & !Test!(!)\BestCode.bat

为什么要使用延迟扩展来输出完整的批处理文件名?

使用命令 ECHO 分配给环境变量(如 FullBatchFileName)的文件/文件夹名称的输出没有包围 " 需要使用 delayed expansion 否则文件/文件夹中的与号name 将被解释为无条件的 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:\ 执行,并在输出中使用"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:\ 执行,并在输出中带有"temp\development & !test!(!)\notgood2"

"temp\development & ()\notgood2"
C:\Temp\Development & ()\NotGood2.bat

可以看出!test!!Test!以及圆括号中的第三个!从两个输出字符串中都消失了,因为!test!!Test!被解释为延迟扩展变量引用并且没有环境变量Test。第三个! 被删除,解释为延迟扩展变量引用的开头,没有匹配的! 标记变量名的结尾。

另见:

【讨论】:

    【解决方案2】:

    %~f0 导致 %0 扩展为完全限定的路径名​​。它们可能相等也可能不相等,具体取决于 %0 的原始值。

    这些修饰符的含义隐藏在For 命令的文档中。

    【讨论】:

    • 在命令提示符窗口中运行call /? for command call 时帮助输出中的隐藏程度与运行for /? for command 时的帮助输出相比更少隐藏对于
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 2021-06-16
    相关资源
    最近更新 更多