Windows批处理文件循环遍历目录以处理文件?

55

我需要编写/使用一个批处理文件,用来为我处理一些图像。

我有一个包含嵌套文件夹的文件夹,每个嵌套文件夹中都有一个包含若干TIF图像的文件夹,每个文件夹中的图像数量不同。我还有一个名为ProcessImages.bat的Windows批处理文件,你可以将这些TIF文件“拖放”到其中(或者在调用bat时明确指定它们的位置); 然后它会基于我拥有的EXE创建一个新的文件夹,并对所有我的图像进行处理。

好的是,因为bat文件使用从您“拖放”到它上面的文件夹的路径,所以我可以选择一个文件夹中的所有TIF并将其“拖放”到其中以执行处理...但是当我手动完成这300个左右的TIF文件夹的处理时,我发现它会让我的系统变得非常缓慢,如果我能只逐个处理这些文件夹(而不是手动操作),那么就好了。

话虽如此...有没有人能指点我(对于一个Windows批处理文件业余爱好者)如何编写一个Windows批处理脚本,我可以从一个目录中调用它,并使其遍历该目录内包含的所有目录... 并依次对每组图像运行我的处理批处理文件?

6个回答

112

你可以在Batch中编写一个递归算法,可以精确控制每个嵌套子目录中所做的操作:

@echo off
call :treeProcess
goto :eof

:treeProcess
rem Do whatever you want here over the files of this subdir, for example:
for %%f in (*.tif) do echo %%f
for /D %%d in (*) do (
    cd %%d
    call :treeProcess
    cd ..
)
exit /b

2
@Aacini。你能解释/评论一下这些/D,%%f命令是做什么的吗?那太好了! - Dexters
2
您可以在以下网址中了解更多有关语法的信息。http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/for.mspx?mfr=true - Sachini Samarasinghe
1
非常棒,你救了我的一天。在程序中使用%CD%%%f作为绝对路径+文件参数。 - Elias ringhauge
1
每当我需要执行类似的批处理文件循环时,我总是回到这个答案。即使多年后仍然非常有帮助。 - Tyler
1
我认为可以省略"call :treeProcess"和 "goto :eof"这两行代码。 - Robert Pollak
3
@RobertPollak:你是正确的!:) 在这种情况下,最后一个 exit /B 也可以省略不写... - Aacini

89

Aacini的解决方案是可行的,但您可以用一行代码来完成:

for /R %%f in (*.tif) do echo "%%f"

不知道过了多少年,但我仍在使用它! - Tyler
我正在使用这个,但出现了一个问题,它会对目录树中的每个文件执行命令,而不仅仅是我指定扩展名的文件。 - Eliezer Miron
2
正如我所说,我的方法可以精确控制在每个子目录中所做的操作。如果该过程需要特定的顺序(例如,首先移动文件,然后删除空的子目录),那么使用for /R就无法实现... - Aacini
1
如果您需要在每个子目录中设置“当前目录”,则此方法无效。 - Robert Pollak
Aacini的作品适用于一个目录,这个作品适用于从您的起始点开始的所有目录。这正是我一直在寻找的!谢谢! - user2010136

17

杰克的解决方案最适合我,但我需要用于网络UNC路径(CIFS / SMB共享),因此需要进行轻微修改:

for /R "\\mysrv\imgshr\somedir" %%f in (*.tif) do echo "%%f"

这种方法的原始提示在这里


/R之后我不能使用变量吗?我将文件/文件夹拖放到批处理文件中,并有一个主循环(FOR %%i IN (%*) DO),检查参数是目录还是文件。如果参数是目录,则有第二个循环,该循环需要递归。我无法使用主循环中的变量使其工作:FOR /R %%i %%f IN (*) DO。我尝试了不同的组合,但/R %%i就是不起作用。 - akinuri
@akinuri 请尝试使用以下命令制作批处理文件:for /R %1 %%f in (*.txt) do echo "%%f",然后将一个文件夹拖放到它上面。 - Jakob Sternberg
这会给出绝对路径。有没有可能得到相对路径呢? - Sourav Kannantha B

3

在这里发布帖子,因为似乎关于这个案件的问题最为普遍。

这里有一个我终于在互联网上找到的老工具:sweep.exe。 它会在当前目录和所有子目录中执行提供的命令,就是那么简单。


假设您有一些处理目录中所有文件的程序(但用例实际上远不止于此):

:: For example, a file C:\Commands\processimages.cmd which contains:
FOR %%f IN (*.png) DO whatever

所以,您想在当前目录和所有子目录中运行此程序:

:: Put sweep.exe in your PATH, you'll love it!
C:\ImagesDir> sweep C:\Commands\processimages.cmd

:: And if processimages.cmd is in your PATH too, the command becomes:
C:\ImagesDir> sweep processimages
优点: 你不必修改原始程序来处理子目录。你可以选择只处理子目录,这个命令非常直观和易于使用。 缺点: 可能会在一些命令中失败(包含空格、引号等等)。例如,请参见此贴

非常棒的解决方案,正好符合我需要尽快完成的工作。 - thehelix

2
我知道这不是递归(遍历枚举的子目录?),但它可能对某些应用程序更有效:
for /F "delims=" %%i in ('dir /ad /on /b /s') do (
    pushd %%i
    dir | find /i "Directory of"
    popd
)

将第三行替换为您可能需要的任何命令。

dir /ad - 仅列出目录

酷的事情是,如果路径中有空格,pushd 不需要引号。


0
rem Replace "baseline" with your directory name
for /R "baseline" %%a in (*) do (
    echo %%a
)

2
请参见“完全基于代码的答案解释”。虽然这可能在技术上是正确的,但它并没有解释为什么它可以解决问题或应该被选为答案。我们应该在帮助解决问题的同时进行教育。 - the Tin Man
1
这个问题已经有五个现有的答案,其中包括一个得票最高、被接受的答案,获得了超过一百个赞。你确定你的解决方案还没有被提出吗?如果不是,为什么你认为你的方法比已经得到社区验证的现有方案更好?在 Stack Overflow 上提供解释总是有用的,但在问题已经得到 OP 和社区满意的情况下,这尤其重要。通过解释你的答案与众不同的地方以及何时可能更受欢迎,帮助读者理解。 - Jeremy Caney

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