Search code examples
windowsfor-loopbatch-filecmdforfiles

At which point does `forfiles` enumerate a directory (tree)?


The command forfiles is intended to enumerate a directory and apply (a) certain command(s) on each item. With the /S the same can be accomplished for a full directory tree.

What happens when the content of the enumerated directory (tree) is changed by the command(s) in the body of the forfiles command?

Supposed we have the directory D:\data with the following content:

file1.txt
file2.txt
file3.txt

The output of forfiles /P "D:\data" /M "*.txt" /C "cmd /C echo @file" when executed in said directory will reflect the above list obviously.

However, what is the output of forfiles when a command in the body modifies the content of the directory? For instance, one of the files in the list is deleted, let's say file3.txt, before it is actually iterated? Or if a new file is created, like file4.txt, before completion of the loop?

How does forfiles /S behave in such a situation? Supposed there are several sub-directories sub1, sub2, sub3, each containing the above list of files; forfiles /S is currently iterating through sub2, sub1 has already been processed, but sub3 not yet; the contents of sub1 and sub3 are changed at that point (when currently walking through sub2 as mentioned); what will be enumerated then? I guess, the change of the content of sub1 won't be recognised, but what about sub3?

I am mainly interested in the behaviour of forfiles since Windows Vista.

Note:
I already posted a very similar question about the for command. However, since forfiles is not a built-in command and has got a completely different syntax I decided to post a separate question instead of extending the scope of the other one.


Solution

  • forfiles will fail to continue enumeration of a renamed folder with an ERROR: The system cannot find the file specified. once you try to use a @-variable which resolves to a nonexistent file. There'll be no error for a deleted file and it will see a newly added file if its name follows the currently processed one in currently used order of enumeration (I've tested it with default alphabetic sort in ascending order). So evidently it doesn't build the entire list of files prior to execution of the command but enumerates them one by one after the custom command completes.

    Depending on what exactly you need to do with forfiles the reliable solutions would be parsing the output of dir /s /b or of robocopy in a list-only mode. Thus you can ensure the list is generated prior to any change.

    • for /f "delims=" %%a in ('dir "d:\data\*.txt" /s /b') do .......
      Suitable for simple enumerations

    • for /f "tokens=*" %%a in ('robocopy /L /njh /njs /ndl ........') do ...
      Suitable for more complicated scenarios like limiting the date span, may require using additional parsing and /v in non-straightforward cases.