如何使用批处理文件中的环境变量更改为目录?

Posted

技术标签:

【中文标题】如何使用批处理文件中的环境变量更改为目录?【英文标题】:How to change to a directory using an environment variable in batch file? 【发布时间】:2021-07-03 07:50:38 【问题描述】:

我尝试创建一个小型应用程序,该应用程序使用默认的 Microsoft 排序功能来整理我的文件夹。我使用了一个名为tosort 的变量,它应该在用户输入时检查目录是否存在。

这是我的代码:

echo off
:retry
set /p tosort=Enter the Directory to sort :
chdir "tosort"
if exist %tosort%\ (
    echo "DIRECTORY FOUND"
    )else (
    goto :retry)

但是,每当批处理到达%tosort%\ 时,就会输出错误消息:

c:\ 不是预期的

【问题讨论】:

用户的预期输入是什么?完全限定路径还是相对路径?如果要更改目录,则必须使用带有百分比符号的实际变量,就像使用 IF 命令一样。 正如@Squashman 所述,您必须使用%tosort% 而不是tosort,但也要使用cd /d "%tosort%",我不明白您为什么要先使用cd然后检查是否存在,而不是检查存在,然后cd 实现某事的方法当然有很多种,与上面的建议相反,我ChDir/PushD"%tosort%",它的成功与否将决定它的存在状态, (不需要If Exist. @Compo 这当然更多是一个偏好问题,但是 FWIW IF EXIST 在 UNC 路径和不同的驱动器号上本地工作,并且实际上并没有改变执行位置,最终可能在某些情况下需要在更改到该目录位置之前的步骤,或者(我通常更喜欢)CD 可以完全避免(因为更改路径比检查更多的工作,并且通常不需要脚本高效运行。)当然我离开了Chdir现在,只是将它修复为在变量周围使用%,我一次想出一件事,但这是 Mofi 对 UNC 提出的公平观点 @Compo 由于可能完全是我的看法,而不是现实,我经常发现PushDPopD 访问UNC 路径的速度很慢,并将其归因于驱动器映射,这通常也是我自己不能使用这些的原因,因为我习惯于没有或很少有备用驱动器分配的 Windows 系统,这会破坏PushDPopD,特别是如果你有一个序列可以打开一个很少的地方,并且可能会忘记PopD,因为在您执行脚本时正确地垃圾收集您的PushD驱动器映射 【参考方案1】:

问题中发布的代码存在多个问题:

    用户根本无法输入任何字符串,在这种情况下,环境变量tosort 仍未定义或仍使用在批处理文件之外定义的值进行定义。 命令chdir "tosort" 没有引用需要使用chdir "%tosort%" 的环境变量的值。 如果当前目录位于不同的驱动器上,使用chdir "%tosort%" 将无法更改当前目录。使用chdir /D "%tosort%" 可以解决这个问题。 如果批处理文件的用户输入UNC 路径,chdir /D "%tosort%" 将失败。解决方案将是pushd "%tosort%",启用命令扩展并匹配popd,如果此命令的执行成功,则将当前目录路径推送到堆栈上并将指定的文件夹路径设置为当前目录,如果使用"%tosort%" 引用的文件夹完全存在。 批处理文件的用户可以输入带有一个或多个" 的字符串,在这种情况下,上面发布的所有命令都将无法正确执行。 if exist %tosort%\ 输入的字符串包含空格或其中一个字符 &()^=;!+,~<>| 失败,因为在执行此命令行时引用的字符串值未用双引号括起来。

所有潜在问题的解决方案是使用以下注释代码:

@echo off
rem Define together with the line above the execution environment completely.
setlocal EnableExtensions DisableDelayedExpansion

:Retry
set "FolderToSort="
set /P "FolderToSort=Enter the directory to sort: "
rem Has the user not input any string at all?
if not defined FolderToSort goto Retry
rem Remove all double quotes from the input string.
set "FolderToSort=%FolderToSort:"=%"
rem Has the user input just double quotes?
if not defined FolderToSort goto Retry

rem Make the directory entered by the user the current directory.
rem The command PUSHD exits with 0 on success and with 1 on failure.
pushd "%FolderToSort%" 2>nul
echo/
if errorlevel 1 (
    echo ERROR: There is no accessible directory:
    echo        "%FolderToSort%"
    echo/
    goto Retry
)
setlocal EnableDelayedExpansion
echo Current directory: !CD!
endlocal
echo/

rem Do something in current directory being the directory entered by the user.
dir

rem Restore the initial current directory.
popd
rem Restore the initial execution environment.
endlocal

注释(cmets)可以去掉,效率更高。

要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

dir /? echo /? endlocal /? goto /? if /? popd /? pushd /? rem /? set /? setlocal /?

【讨论】:

【参考方案2】:

您的代码可能只是因为目录路径中有空格而失败,如果路径中有空格,则需要在其周围使用双引号。 "%tosort%\"

我对游览代码进行了一些重构,使其更具可读性并利用函数,包括一个主函数。

通过使用Call :Label,我们移动到函数标签,并在函数完成时返回并执行下一行。

这意味着脚本的结尾是Endlocal 药水。

在您的脚本中使用SetLocalendlocal 是一种很好的做法,这样如果您从另一个调用一个脚本中生成的更改,则另一个脚本中不存在。 (如果你有一些想要返回的变量,你可以将它们放在exit /b之前的括号块中)

函数最好以GOTO :EOF 结尾,:EOF 标签是文件末尾的占位符,因为脚本或函数会一直读取到文件末尾。文件末尾的函数可以将其关闭,但最好将其保留并统一声明所有函数。

编辑:由于您可能想要检查该目录是否存在并带有尾随 \,然后稍后将其不带尾随 \ 用于其他一些命令,并且由于用户可以自己添加尾随 \,并且可能会将路径用双引号 " 自己括起来我正在修改它以检查所有内容。

请注意,REM 是用于注释脚本的备注命令。

如果您将脚本顶部的ECHO OFF 更改为ECHO ON,备注将与正在运行的命令一起打印,您将能够看到脚本在其执行中的位置。

@(SETLOCAL
  echo off
)

Call :Main

( Endlocal
  Exit /b
)

:Main
  REM Call the SetCheckDir Function
   Call :SetCheckDir

 REM Change directory to the path that we found
  chdir "%tosort%"

REM This following line ends the Main Function
Goto :EOF

:SetCheckDir

  REM Check for the path from the user
   SET /p "tosort=Enter the Directory to sort: "

  REM Clear off double qoutes
   SET "TmpVar=%tosort:"=%"

  REM Add Trailing backslash
   IF /I "%TmpVar:~-1%" NEQ "\" SET "TmpVar=%TmpVar%\"

  REM Test if the Directory path is good:
   IF NOT EXIST "%TmpVar%" ( GOTO :SetCheckDir )

  REM Set the original variable to the found path, minus the trailing backslash
   SET "tosort=%TmpVar:~0,-1%"
Goto :EOF

【讨论】:

以上是关于如何使用批处理文件中的环境变量更改为目录?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用批处理文件更改当前工作目录

文本文档格式下,如何把一列数据改为连续的行数据?

在 Windows 批处理文件中将反斜杠更改为正斜杠

如何使用 Windows 命令行环境查找和替换文件中的文本?

如何使用Windows命令行环境查找和替换文件中的文本?

批处理文件注册OCX