如何在批处理文件中递归搜索文件,但只对找到文件的实例进行操作?

4

我的脚本的目标是递归搜索单个文件名(在不同文件夹中存在该名称的文件),给定起始路径并输出找到的每个文件的路径,不包括名称和扩展名。

由于某种原因,我卡在这里了整个上午。我已经编写了以下代码。

@echo off

for /r D:\Workspaces\fwarrener-lglesias\Example\Example\Clients %%x in (EnterpriseSettings.config) do (
    echo %%~nxx
    echo %%~dpx
)

我之前从其他人的回答和文档中得出的印象是,只有在括号内找到文件时,才会执行“do”子句中的命令。然而,当执行并将其导入文件时,输出了大量不必要的行,其中甚至包括它所在的目录,即使没有找到文件。我对此感到困惑,因为我认为指定集合的整个意义在于只有在找到文件名的情况下才会执行“do”中的命令。

D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\Config\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\Config\Stage\

请问有谁能够告诉我,我如何误解了for循环或语法的使用?


你不考虑将这个迁移到 Powershell 中吗?因为 PS 对 FileSystem 有更多的控制权。运行 batch 的特定原因是什么? - Alex
@Alex 我之前没有考虑到这一点,因为我不需要多次执行此操作,而且这实际上只是一个更大任务的小组件。我正在尝试使用微软的TFS CLU来以编程方式编辑和签出文件,这些路径将是我解析到TFS映射的路径。我认为在批处理文件中完成这个任务应该是相当简单的。:) 我需要在批处理中完成它,因为这段代码将被放在批处理脚本中,用于自动化一些源代码控制的工作。 - Felipe Warrener-Iglesias
@ThomasWeller 我想要输出目录,但仅当文件在其中时。这就是我认为 in() 的整个意义所在?D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\Config\Stage\ 是正确的路径。之前的其他路径是它遍历到那个路径下吗? - Felipe Warrener-Iglesias
使用 EnterpriseSettings*.config 可能会解决问题,但可能会包含错误的结果。 - Thomas Weller
1
至少看起来不像是一个错误。这已经有一段时间了:https://ss64.com/nt/for_r.html 还要注意该网站上说“必须使用通配符”。看看旧操作系统甚至是DOS的帮助文本会很有趣。 - Thomas Weller
显示剩余4条评论
4个回答

1

对我来说,使用 DIR 命令似乎更为明显。请参阅 DIR /? 命令的输出中 /A:-D-S-L 的含义。

FOR /F "tokens=*" %%x IN ('DIR /S /B /A:-D-S-L "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\EnterpriseSettings.config"') DO (
    echo "%%~nxx"
    echo "%%~dpx"
)

@aschipfl - 谢谢。我同意。我已经做出了更改,还有一点点。 - lit

1
您的代码问题很可能是由于For /RFor /D期望通配符模式引起的。
解决方法如下:
  • 使用*通配符,例如("EnterpriseSettings.conf*g")
  • 使用?通配符,例如("EnterpriseSettings.c?nfig")
    需要注意的是,即使仔细放置通配符,也有可能匹配到非必需文件。
  • 使用不同的方法,例如带有递归选项的DirWhere命令。
    这应该只匹配精确的文件名,如下面的示例所示.

@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion

Set "dirBase=D:\Workspaces\fwarrener-lglesias\Example\Example\Clients"
Set "fileName=EnterpriseSettings.config"

If /I Not "%__CD__%"=="%dirBase%\" (
    PushD "%dirBase%" 2>Nul && (Set "_=$") || Exit /B
)

For /F "Delims=" %%A In ('Dir /B/S/A-D-S-L "%fileName%" 2^>Nul') Do Echo %%~dpA
Pause

If "%_%"=="$" PopD
EndLocal

0

正如这个答案所示,使用dir命令是一个好的解决方案,我更倾向于这种方法。

另一种方法是像你已经做的那样使用for /R,但要添加if exist,如下所示:

for /R "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients" %%x in ("EnterpriseSettings.config") do (
    if exist "%%~x" if not exist "%%~x\" (
        echo %%~nxx
        echo %%~dpx
    )
)

if not exist 部分加上项目和尾随的 \,可以排除与匹配名称相同的目录。

另一种方法是添加通配符(在本例中为 ?)以强制 for 访问文件系统并检查匹配的文件,但针对误报过滤结果:

for /R "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients" %%x in ("EnterpriseSettings?.config") do (
    if /I "%%~nxx"=="EnterpriseSettings.config" (
        echo %%~nxx
        echo %%~dpx
    )
)

-1

我已经重新编写了我的批处理脚本。

请告诉我这是否对您有所帮助:


@ECHO OFF

SET path=C:\Users\<USER>\<DIRS>
SET filename=EnterpriseSettings*.config

For /R %path% %%f in (%filename%) do (
    echo %%~pf
)

PAUSE

我还使用了~p习惯用法,它是仅提取路径,可在以下链接中找到:批处理文件和更多习惯用语中的文件名解析


1
你没有解释OP的问题在哪里,他犯了什么错误。你没有考虑到OP的要求。他不仅想列出文件,还需要对它们进行操作(见%%~nxx),这是使用dir无法实现的。你的解决方案无法实现这一点。 - Thomas Weller
@FelipeWarrener-Iglesias,如果您有现有的代码并希望集成解决方案,请编辑您的问题以包含该代码。不要期望回答者花费时间和精力提供不符合您隐藏需求的答案。您提供的问题只是echo了带扩展名的名称和驱动器路径! - Compo
1
@Compo:这正是 [MCVE] 应该做的事情:尽可能少地编写代码,以演示问题,而不会在其他要求上添加太多细节。 - Thomas Weller
我误解了问题,目前正在努力寻找解决方案。 - Alex
@Compo我拒绝将其接受,因为它没有解释我的for逻辑为什么会出现这种情况,这正是我的问题所在。解决这个问题并让for逻辑正常工作可以使代码与我的其他代码兼容...我问了一个清晰的问题,Alex说他误解了我的问题。我给他点赞并让他知道他的答案在某种程度上是有用的,因为我可以快速生成路径列表并将其添加到我们的文档中。 - Felipe Warrener-Iglesias
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接