为什么%CD%在PushD的for循环中不起作用

时间:2018-12-05 12:38:07

标签: loops batch-file pushd

我想运行一个.bat脚本,该脚本创建一个文件,并使用与它所在的文件夹相同的名称进行保存。我希望它从一个地图开始并遍历子地图。 我从下面的代码开始,并在其中一个子图中运行它。可行,我得到一个带有子图名称的文件。

FOR /D %%I IN ("%CD%") DO SET _LAST_SEGMENT_=%%~nxI
ECHO Last segment = "%_LAST_SEGMENT_%"
echo.>%_LAST_SEGMENT_%.mp4
pause

所以现在我只需要将它放在for循环中。所以我做了下面的代码,这是行不通的。看来%CD%是指.bat文件所在的父地图(子文件夹),而不是我的子地图(video1,video2等)。

Set Base=C:\Video\subfolders
FOR /R "%Base%" %%F IN (.) DO (
    PushD "%%F"
        FOR /D %%I IN ("%CD%") DO SET _LAST_SEGMENT_=%%~nxI
        echo %CD%
        ECHO Last segment = "%_LAST_SEGMENT_%"
        echo.>%_LAST_SEGMENT_%.mp4
    PopD
)
Pause

输出:

C:\Video\subfolders>Set Base=C:\Video\subfolders
C:\Video\subfolders>FOR /R "C:\Video\subfolders" %F IN (.) DO (
PushD "%F"
 FOR / %I IN ("C:\Video\subfolders") DO SET _LAST_SEGMENT_=%~nxI
 echo C:\Video\subfolders
 ECHO Last segment = ""
 echo.   1>.mp4
 PopD
)
C:\Video\subfolders>(
PushD "C:\Video\subfolders\."
 FOR / %I IN ("C:\Video\subfolders") DO SET _LAST_SEGMENT_=%~nxI
 echo C:\Video\subfolders
 ECHO Last segment = ""
 echo.   1>.mp4
 PopD
)
C:\Video\subfolders>SET _LAST_SEGMENT_=subfolders
C:\Video\subfolders
Last segment = ""
C:\Video\subfolders>(
PushD "C:\Video\subfolders\video1\."
 FOR / %I IN ("C:\Video\subfolders") DO SET _LAST_SEGMENT_=%~nxI
 echo C:\Video\subfolders
 ECHO Last segment = ""
 echo.   1>.mp4
 PopD
)
C:\Video\subfolders\video1>SET _LAST_SEGMENT_=subfolders
C:\Video\subfolders
Last segment = ""
C:\Video\subfolders>(
PushD "C:\Video\subfolders\video2\."
 FOR / %I IN ("C:\Video\subfolders") DO SET _LAST_SEGMENT_=%~nxI
 echo C:\Video\subfolders
 ECHO Last segment = ""
 echo.   1>.mp4
 PopD
)
C:\Video\subfolders\video2>SET _LAST_SEGMENT_=subfolders
C:\Video\subfolders
Last segment = ""
C:\Video\subfolders>(
PushD "C:\Video\subfolders\video3\."
 FOR / %I IN ("C:\Video\subfolders") DO SET _LAST_SEGMENT_=%~nxI
 echo C:\Video\subfolders
 ECHO Last segment = ""
 echo.   1>.mp4
 PopD
)
C:\Video\subfolders\video3>SET _LAST_SEGMENT_=subfolders
C:\Video\subfolders
Last segment = ""
C:\Video\subfolders>Pause
Press any key to continue . . .

我看到了下面的链接,其中解释了如何使用setlocal enabledelayedexpansion,但我无法使它正常工作。

https://superuser.com/questions/503488/why-doesnt-cd-work-after-using-pushd-to-a-unc-path

任何建议将不胜感激

2 个答案:

答案 0 :(得分:1)

您似乎想要以下内容:

@echo off
for /F "delims=" %%I in ('dir "C:\Video\subfolders\*" /AD-H /B /S 2^>nul') do (
    pushd "%%I"
    echo/>"%%~nxI.mp4"
    popd
)

命令pushdpopd并不是必需的,如以下代码所示:

@echo off
for /F "delims=" %%I in ('dir "C:\Video\subfolders\*" /AD-H /B /S 2^>nul') do (
    echo Directory is: %%I
    echo/>"%%I\%%~nxI.mp4"
)

命令 FOR 在以cmd.exe /C开头的单独命令过程中在后台命令行中运行:

dir "C:\Video\subfolders\*" /AD-H /B /S 2>nul

命令 DIR 输出以处理此后台命令过程的 STDOUT

  • 由于选项/B以纯格式显示,仅由于选项/S而具有全路径的所有名称
  • 由于选项/AD-H而处于非隐藏目录中(属性目录而不是隐藏目录)
  • 在指定目录C:\Video\subfolders及其所有子目录中。

DIR 输出的错误消息,用于在未找到C:\Video\subfolders的整个目录树中找到任何目录条目时处理 STDERR ,该错误消息通过将其重定向到设备< strong> NUL 。

阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>必须在 FOR 命令行上使用脱字符号^进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir命令行。

FOR 将输出捕获到已启动命令进程的 STDOUT ,并逐行处理该输出,而忽略空行,并且默认情况下还以分号开头的行在这里不会发生。

FOR 还将每行分成空格/制表符的子字符串,并且仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I。目录名可以有空格,因此,delims=用于定义字符串定界符的空列表,从而导致始终将分配给循环变量I的当前完整完整合格目录名分配给捕获的 DIR 输出。

不带路径的目录名称用%%~nxI引用,它是最后一个反斜杠之后的字符串。目录名称也可以包含folder.name之类的点,也可以包含.FolderName之类的点开头,尽管两者在Windows上都不常见。因此,有必要使用%%~nxI(名称和扩展名),而不仅仅是%%~nI,因为 FOR 不会验证用%%I引用的字符串是否为文件或目录名称。

%%~nI引用最后一个\之间的字符串 (或与Linux路径兼容的/,首先替换为\)如果没有\(或/,则在字符串的所有处都加反斜杠(或反斜杠),如果没有{ .完全在已经确定名称字符串字符串结束(如果没有点)之后。 %%~xI引用以最后一个目录分隔符之后的最后一个点开头的字符串。因此,分配给循环变量I的字符串必须不是真正存在的文件/文件夹的文件/文件夹名称,尽管在这种情况下就是这种情况。如果%%~nxI包含以I(或\)结尾的字符串,则/将为空字符串。

请勿将可在没有变量或没有修饰符的情况下使用循环变量引用的字符串分配给环境变量,因为这将需要使用delayed expansion,如命令 SET 所述>在命令提示符窗口set /?中运行时的输出。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • dir /?
  • echo /?
  • for /?
  • popd /?
  • pushd /?

另请参阅DosTips论坛主题ECHO. FAILS to give text or blank line - Instead use ECHO/

有问题的第二批处理文件代码不起作用,因为未使用延迟扩展,或者避免使用在命令块内定义/修改并使用语法%variable%在同一命令块内引用的环境变量。 Windows命令处理器cmd.exe在执行外部 FOR 之前,先解析从第一个 FOR (到匹配的)的整个命令块。第一次。请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?,在此预处理阶段,此命令块中的所有%variable%引用已被引用的环境变量的当前值替换。因此,最终在迭代外部 FOR 上执行的代码不再包含任何%variable%环境变量引用,因为可以在执行命令行之前在cmd.exe输出的命令行上看到它。

答案 1 :(得分:0)

Mofi's answer解决了OP的问题时,实际上并没有回答最初提出的问题。

%CD%FOR循环中不起作用的原因是您需要启用“ delayed expansion

例如:

SETLOCAL EnableDelayedExpansion
FOR %%i in (foo bar) DO (
    pushd %%i
    echo CD with delayed expansion: !CD!
    echo CD without it: %CD%
)

假设运行该目录时存在“ foo”和“ bar”目录,则应该看到!CD!提供了正确的路径。

更多示例:Example of delayed expansion in batch file