For /d /r loop not traversing sub-directories for finding desired directory recursively in Batch/CMD script

For /d /r loop not traversing sub-directories for finding desired directory recursively in Batch/CMD script

如问题标题所述,我有一个 Batch/CMD(OS: Windows 10 64Bit) 脚本来遍历 %LocalAppData% 中的子文件夹脚本为Chrome,递归查找并列出任意位置包含单词Cache的所有文件夹。

我想出的依赖for /d /r循环的脚本是这样的:

@echo off && setlocal EnableDelayedExpansion
if /i "%1" equ "chrome" (
    set "subPath0=\Google"
    set "subPath1=\User Data"
    for /d /r "%LocalAppData%!subPath0!\%1" %%i in (*Cache*) do (
        echo "%%i"
    )
) else (
    for /d /r "%Appdata%\%1" %%i in (*Cache*) do (
        echo "%%i"
    )
)

但是无论我是否像 (*Cache*^) 那样转义 for 循环中的右括号,上面的循环都没有递归地列出任何 *Cache* 目录,即使实际上有缓存 路径内的文件夹(for 循环所在的文件夹是运行)在User Data 文件夹内。

所以谁能指出我在这里做错了什么并帮助解决这个问题?

注意: 我知道 Powershell 是 Batch/CMD 的不错选择,但这应该是较大脚本的一部分,如果 suggestions/fixes 在Batch/CMD.

FOR 命令中删除路径并改用 PUSHD。

@echo on
setlocal EnableDelayedExpansion
if /i "%1" equ "chrome" (
    set "subPath0=\Google"
    set "subPath1=\User Data"
    pushd "%LocalAppData%!subPath0!\%~1"
    for /D /R %%i in (*Cache*) do (
        echo "%%i"
    )
    popd
) else (
    pushd "%Appdata%\%1"
    for /d /r %%i in (*Cache*) do (
        echo "%%i"
    )
    popd
)

为什么不将其简化为一个 FOR 命令?

@echo on
setlocal EnableDelayedExpansion
if /i "%~1" equ "chrome" (
    set "subPath0=\Google"
    set "subPath1=\User Data"
    set "searchpath=%LocalAppData%!subPath0!\%1"

) else (
    set "searchpath=%Appdata%\%~1"
)

for /d /r "%searchpath%" %%i in (*Cache*) do echo "%%i"

强烈推荐使用:

@echo off & setlocal EnableExtensions DisableDelayedExpansion
if /I not "%~1" == "chrome" goto SearchAppdata

for /D /R "%LocalAppData%\Google\%~1" %%i in (*Cache*) do echo "%%i"
goto EndBatch

:SearchAppdata
for /D /R "%Appdata%\%~1" %%i in (*Cache*) do echo "%%i"

:EndBatch
endlocal

所有改动的解释:

  1. 命令 echo off 永远不会失败,因此在第一行中使用无条件运算符 & 而不是条件运算符 &&。有关详细信息,请参阅 single line with multiple commands using Windows batch file

  2. 批处理文件需要启用命令扩展。出于这个原因,建议显式启用命令扩展,而不是依赖于在批处理文件之外启用。

  3. 明确不使用延迟扩展,因为这会导致 %~1%%i%LocalAppdata%%Appdata% 扩展为字符串将感叹号解释为文字字符后,一个或多个 ! 将不再被正确处理。

  4. 字符串比较运算符==用于比较两个字符串而不是整数比较运算符equ也适用于字符串,但不同于字符串比较运算符一些罕见的用例。有关详细信息,请参阅

  5. 传递给批处理文件的第一个参数字符串在开始和结束时被删除 " 如果被包含在 " 中,否则批处理由于严重的语法错误,文件处理已经在第二行停止。如果有人使用 google" 之类的东西运行批处理文件,即在参数字符串的末尾有一个双引号,但在开头没有双引号,这种情况仍然会发生。也可以使用额外的命令行来处理这种极其罕见的用例,但这里真的没有必要,因为这是程序或用户启动批处理文件的语法错误。

  6. 命令GOTO用于避免命令块,从而可以在不延迟扩展的情况下引用所有环境变量。

命令FOR不支持在/R之后指定的路径内延迟扩展。这是 DosTips 论坛主题 Limitation in for /r command 中记录的此命令的已知问题。解决方案是避免在 /R.

之后指定的目录路径字符串内延迟扩展

可以在 CD(不适用于 UNC 路径)或 PUSHD(也适用于启用了命令扩展的 UNC 路径)之前使用) 和循环后的 POPD 。或者使用命令 DIR 由另一个在后台启动的命令进程执行,其优点是还可以找到名称中包含字符串 cache 的隐藏目录 for /D 忽略,而 for /R 也遍历隐藏目录。

@echo off & setlocal EnableExtensions DisableDelayedExpansion
if /I not "%~1" == "chrome" goto SearchAppdata

for /F "delims=" %%i in ('dir "%LocalAppData%\Google\%~1\*Cache*" /AD-L /B /S 2^>nul') do echo "%%i"
goto EndBatch

:SearchAppdata
for /F "delims=" %%i in ('dir "%Appdata%\%~1\*Cache*" /AD-L /B /S 2^>nul') do echo "%%i"

:EndBatch
endlocal

在这种情况下,由于选项 /AD-L(属性目录,但不是属性 link),重新分析点(目录连接,符号 links)被明确忽略,参见 SS64 - MKLINK 有关 link 在 Windows 上的更多信息。