Batch file “forfiles”在哪一点枚举目录(树)?
forfiles命令用于枚举目录并对每个项目应用特定命令。使用Batch file “forfiles”在哪一点枚举目录(树)?,batch-file,for-loop,cmd,forfiles,Batch File,For Loop,Cmd,Forfiles,forfiles命令用于枚举目录并对每个项目应用特定命令。使用/S可以为完整的目录树实现同样的功能 当forfiles命令体中的命令更改枚举目录(树)的内容时,会发生什么情况 假设我们有目录D:\data,包含以下内容: file1.txt file2.txt file3.txt 在上述目录中执行时,forfiles/p“D:\data”/M“*.txt”/C“cmd/C echo@file”的输出将明显反映上述列表 但是,当正文中的命令修改目录的内容时,forfiles的输出是什么?例如,列
/S
可以为完整的目录树实现同样的功能
当forfiles
命令体中的命令更改枚举目录(树)的内容时,会发生什么情况
假设我们有目录D:\data
,包含以下内容:
file1.txt
file2.txt
file3.txt
在上述目录中执行时,forfiles/p“D:\data”/M“*.txt”/C“cmd/C echo@file”
的输出将明显反映上述列表
但是,当正文中的命令修改目录的内容时,forfiles
的输出是什么?例如,列表中的一个文件在实际迭代之前被删除,比如说file3.txt
?或者如果在循环完成之前创建了一个新文件,比如file4.txt
在这种情况下,forfiles/S
的行为如何?假设有多个子目录sub1
,sub2
,sub3
,每个子目录都包含上述文件列表forfiles/S
目前正在迭代sub2
,sub1
已经处理,但sub3
尚未处理;sub1
和sub3
的内容在该点发生更改(如前所述,当前通过sub2
时);那么将列举什么?我想,sub1
的内容变化不会被识别,但是sub3
呢
自从Windows Vista以来,我主要对文件的行为感兴趣
注意:我已经发布了
for
命令。然而,由于forfiles
不是内置命令,并且语法完全不同,因此我决定发布一个单独的问题,而不是扩展另一个问题的范围。forfiles
将无法继续枚举重命名的文件夹,并出现错误:系统无法找到指定的文件。
一旦尝试使用解析为不存在文件的@-变量。删除的文件不会出现错误,如果其名称按照当前使用的枚举顺序(我已经用默认的字母升序排序)跟随当前处理的文件,它将看到新添加的文件。因此,显然它不会在执行命令之前构建整个文件列表,而是在自定义命令完成后逐个枚举它们
可靠的解决方案是以列表模式解析dir/s/b
或robocopy
的输出,具体取决于您需要对文件执行什么操作。因此,您可以确保在进行任何更改之前生成列表
对于/f“delims=“%%a in('dir“d:\data\*.txt”/s/b'),执行……
适用于简单枚举对于('robocopy/L/njh/njs/ndl……。)中的/f“令牌=*”%%a,执行…
适用于更复杂的场景,如限制日期跨度,在非直接的情况下可能需要使用额外的解析和/v
对文件进行了一些测试
——以下是结果
目的和范围
本文中的测试用例旨在证明在迭代所有(子)项之前,forfiles
是否完成给定目录(树)的枚举
下面的列表显示了此处的测试所涵盖的模式:
- 文件模式(
)总是/M
李>*.txt
- 文件模式(
)只匹配文件,而不匹配目录李>/M
- 始终存在给定的根搜索路径(
)李>/P
- 在主体(
)中,仅使用内部/C
命令(前缀为cmd.exe
)李>cmd/C
- 非递归操作,迭代数个和100个文件李>
- 仅在几个目录上迭代的递归操作(
)李>/S
- 递归操作(
),以一个级别的深度在目录层次结构上迭代李>/S
- 根本不使用文件期过滤器(
)李>/D
- 目录(树)内容仅在某个迭代中修改一次李>
- 未修改文件(内容),因此未检测到大小和日期/时间的更改李>
forfiles
按字母顺序枚举的原因。)操作系统为Microsoft Windows 7 64位(版本6.1.7601) 先决条件 在执行各个命令行之前,需要提前简化各个测试步骤中描述的所需目录树。
使用的根目录
D:\Data
中不得存在任何其他文件或目录
forfiles/S
,递归
对于本文中的测试用例,必须建立以下目录树:
D:\Data\
+---sub1\
| file1.txt
| file2.txt
| file3.txt
+---sub2\
| file1.txt
| file2.txt
| file3.txt
+---sub3\
| file1.txt
| file2.txt
| file3.txt
+---sub4\
| file1.txt
| file2.txt
| file3.txt
+---sub5\
file1.txt
file2.txt
file3.txt
我使用以下代码行进行设置:
@(pushd D:\Data
md sub1 & pushd sub1 & rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt & popd
md sub2 & pushd sub2 & rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt & popd
md sub3 & pushd sub3 & rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt & popd
md sub4 & pushd sub4 & rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt & popd
md sub5 & pushd sub5 & rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt & popd
rd /S /Q sub6
popd) > nul 2>&1
我的意图是等待文件夹
sub3
中的itemfile2.txt
被迭代,然后完成以下任务:
- 在当前迭代的子3中,
- 删除
(已迭代)李>file1.txt
- 删除
(尚未迭代)李>file3.txt
- 创建
(新项目,尚未迭代)李>file4.txt
- 删除
- 删除容器
(已迭代)李>sub1
- 删除容器
(尚未迭代)李>sub4
- 通过将
重命名为file2.txt
,更改file4.txt
(已迭代)的内容李>sub2
- 通过重命名
file2更改
(尚未迭代)的内容sub5
forfiles /S /P "D:\Data" /M "*.txt" /C "cmd /C (if @relpath==\".\sub3\file2.txt\" (del file1.txt & del file3.txt & rem.> file4.txt & rd /S /Q ..\sub1 & rd /S /Q ..\sub4 & ren ..\sub2\file2.txt file4.txt & ren ..\sub5\file2.txt file4.txt & md ..\sub6 & rem.> ..\sub6\file4.txt)) & echo @path"
"D:\Data\sub1\file1.txt" "D:\Data\sub1\file2.txt" "D:\Data\sub1\file3.txt" "D:\Data\sub2\file1.txt" "D:\Data\sub2\file2.txt" "D:\Data\sub2\file3.txt" "D:\Data\sub3\file1.txt" "D:\Data\sub3\file2.txt" "D:\Data\sub3\file3.txt" ERROR: The system cannot find the file specified. "D:\Data\sub5\file1.txt" "D:\Data\sub5\file3.txt" "D:\Data\sub5\file4.txt"
D:\Data\ file1.txt file2.txt file3.txt
@(pushd D:\Data rem.> file1.txt & rem.> file2.txt & rem.> file3.txt & del file4.txt popd) > nul 2>&1
forfiles /P "D:\Data" /M "*.txt" /C "cmd /C (if @fname==\"file2\" (del file1.txt & del file3.txt & rem.> file4.txt)) & echo @file"
"file1.txt" "file2.txt" "file3.txt"
D:\Data\ file0.txt file1.txt file2.txt ... file99.txt
@(pushd D:\Data del file100.txt & del file999.txt for /L %%N in (0,1,99) do (echo.%%N> file%%N.txt) popd) > nul 2>&1
forfiles /P "D:\Data" /M "*.txt" /C "cmd /C (if @fname==\"file1\" (ren file99.txt file999.txt)) & echo @file"
"file0.txt" "file1.txt" "file10.txt" "file11.txt" ... "file98.txt" "file999.txt"
forfiles /P "D:\Data" /M "*.txt" /C "cmd /C (if @fname==\"file1\" (ren file99.txt file100.txt)) & echo @file"
"file0.txt" "file1.txt" "file10.txt" "file11.txt" ... "file98.txt"
forfiles /P "D:\Data" /M "*.txt" /C "cmd /C (if @fname==\"file1\" (ren file0.txt file999.txt)) & echo @file"
"file0.txt" "file1.txt" "file10.txt" "file11.txt" ... "file98.txt" "file99.txt" "file999.txt"