Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Batch file “forfiles”在哪一点枚举目录(树)?_Batch File_For Loop_Cmd_Forfiles - Fatal编程技术网

Batch file “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的输出是什么?例如,列

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
  • 目录(树)内容仅在某个迭代中修改一次
  • 未修改文件(内容),因此未检测到大小和日期/时间的更改
测试设置 所有测试都在NTFS格式磁盘上执行。(这可能是所有文件都由
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
中的item
file2.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"