最后一个参数中的正斜杠导致批处理文件 ("%~dp0") 目录的路径发生变化

Forward slash in last argument causes path to directory of batch file ("%~dp0") to change

我正在学习如何在批处理脚本中使用参数,并最终创建了某种模板来读取参数和设置参数

@echo off
SetLocal EnableDelayedExpansion
set needextra=
set errstat=
set noflag=
set param_f=Not set yet
set param_g=You didn't use G-flag

:readARGS
IF [%1] == [] goto :endARGS
call :arg_%1 2> nul
IF ERRORLEVEL 1 call :arg_default %1
SHIFT
IF DEFINED needextra (
    set %needextra%=%~1
    SHIFT
    set needextra=
)
goto :readARGS
:endARGS
echo path to directory of batch script: %~dp0
echo    - noflag:  !noflag!
echo    - param_f: !param_f!
echo    - param_g: !param_g!
EndLocal
exit /b 0

打印目录的第一个 echo 对我的问题很重要(见后) 之后,我为每个标志(arg_/flag)和一个没有标志的参数(arg_default)创建了一个函数:

:arg_/f           -- flag f: set param_f to value of next argument
set needextra=param_f
exit /b 0

:arg_/g           -- flag g: just set the param_g to a value
set param_g=You used the G-flag
exit /b 0

:arg_default      -- default, neither flag f or g: just set the noflag
echo noflag=%~1
exit /b 0

当我把所有东西都放在批处理文件中时,假设 C:\Users\user\scripts\params.bat 并将目录放在我可以执行脚本的路径中:

> params "just an arg"
path to directory of batch script: C:\Users\user\scritpts\
   - noflag:  just an arg
   - param_f: Not set yet
   - param_g: You didn't use G-flag
> params another /G /F "this is f"
path to directory of batch script: C:\Users\user\scritpts\
   - noflag:  another
   - param_f: this is f
   - param_g: You used the G-flag

我把它放在函数中的事实允许我以我希望的任何顺序输入参数,但是如果我把 G 标志放在最后,我会得到这个奇怪的行为:

> params /F "this is f again" bizar /G
path to directory of batch script: C:\
   - noflag:  bizar
   - param_f: this is f again
   - param_g: You used the G-flag

%~dp0returns只有C:\!我尝试使用其他参数,将批处理文件移动到另一个目录,在目录中调用它,%~dp0 只返回 C:\。事实上,每次最后一个参数包含一个“/”时,%~dp0 的行为将 "strangely" 如下例所示:

> params /G /F stranger "what happens /here"
path to directory of batch script: C:\Users\user\script\what happens \
   - noflag:  what happens /here
   - param_f: stranger
   - param_g: You used the G-flag

有人可以解释一下为什么会这样吗?我不知道为什么,也无法在网上找到任何东西。我用 Windows 10

非常感谢您提供的任何帮助。

我建议 %~d0 在执行 SHIFT 命令后可能不可靠,所以我会在开始时保存它的值。

也许 This question 可以帮到您。不过我还是会先存~dp0...

这是为什么

params "just an arg"
params another /G /F "this is f"

有效,这

params /G /F stranger "what happens /here"
params /F "this is f again" bizar /G

不起作用是...在这两种情况下都不起作用!

正如 Magoo 指出的那样,您的问题是 shift 命令。默认情况下,它会移动 all 个参数,因此第十个参数存储在 %9 中,旧的 %9 存储在 %8 ... 中%1 存储在 %0 中,丢失了对当前批处理文件的引用。

在您的代码中,您正在移动所有参数,直到所有参数都被处理。这就把最后一个参数留在了%0里面,这时候事情就变得有趣了。

当请求 %~dp0 时,最后一个参数存储在 %0 中,当我们请求参数中引用的元素的驱动器和文件夹时,cmd 尝试解决它假设你知道你要求什么并且变量包含对文件系统中元素的有效引用,将其转换为绝对路径然后检索请求的元素。

这里你遇到过两种情况

  • %0 只包含一个没有斜杠或反斜杠的简单字符串。 cmd 将其作为存储在当前活动目录中的文件名处理,因此,当您请求驱动器和路径时,将检索当前活动目录的驱动器和路径。在您的 "working" 个案例中,您以
  • 结尾
"C:\Users\user\script\just an arg" -> %~dp0 = "C:\Users\user\script\"
"C:\Users\user\script\this is f"   -> %~dp0 = "C:\Users\user\script\"
  • %0 包含带有斜杠或反斜杠的字符串。同样的情况是,在 BUT 之前,字符串包含一个相对路径(第一个失败案例),该路径以当前活动目录或根文件夹的路径(第二个失败案例)为前缀,因此您以
  • 结尾
"C:\Users\user\script\what happens /here" -> %~dp0 = "C:\Users\user\script\what happens "
"C:/g" -> %~dp0 = "C:\"

你怎么解决的?

根据 Magoo 的建议,最简单的解决方法是在对参数进行任何移动之前保存 %0 参数的值。

另一种选择是将 shift 命令更改为 shift /1,以表示移位将从第一个参数开始,而 %0 保持不变。

如果可以使用此选项中的 none,您仍然可以从子例程中检索对批处理文件的引用

@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Ensure %0 is discarded    
    shift
    echo %0

    call :getCurrentBatchFolder dp0
    echo %dp0%

    exit /b

:getCurrentBatchFolder returnVar
    set "%~1=%~dp0"
    goto :eof