Question

I've written the following batch file to create multiple files using FOR loop:

@echo off  
cls  
FOR /L %%i IN (1 1 10) DO (  
    echo.> file%%i.txt  
    IF ERRORLEVEL 0 echo Successfully created file 'file%%i.txt'.  
)  
dir /b *.txt  
FOR %%i IN (*.txt) DO (  
    echo.> file%%i.txt
    IF ERRORLEVEL 0 echo Successfully created file 'file%%i.txt'.  
)

Here, 10 files (viz. file1.txt .... file10.txt) are created in the first FOR loop.
And in the second FOR loop I've used these files to frame the name of next new files. (viz.filefile1.txt.txt ... filefile10.txt.txt)

But, an extra file is being created : filefilefile1.txt.txt.txt
What logical issue is causing the creation of this extra file ?

Was it helpful?

Solution

EDITED - Seems i've not explained it properly and people doesn't see how it works. My fault. I'm going to try to explain it better.

The reason is the way the for command works internally.

When the line for var in (files) is reached, the directory is checked to see if any files match and need to be processed.

Then, for command (cmd really), issues a directory query to enumerate the files. This query returns only the first file in set. If there are any aditional files that match the file mask in for command, a flag is set that indicates to the caller (cmd) that there are more files to be processed, but the list of the remaining files is not yet retrieved.

When execution of code inside for reachs the end of an iteration, and there are files pending to be read, a query is sent to get the remaining of the list of files pending to be processed and that match the for file selection.

System fills a buffer with the list of files remaining. If at that point the list of files is short enough to be full readed in buffer, the query will not be repeated. If the list of files is big enough to not fit in buffer, partial list is retrieved and when files in retrieved list are processed, the query will be sent again to get more files to process.

Number of files in buffer depends on length of filename. Shorter filenames, more files in buffer and less queries to filesystem.

This behaviour (retrieving remaining list of files at end of first file processing) is only done if the query for files returns that there are files pending. When one query does not return that flag, no more files are retrieved.

EXCEPTIONS

If working in NTFS, the files only get included in "requeries" if they are alphabetically greater than the last file that has been processed in for command.

If working if FAT, the query will include all new file generated that match the for command file selection independly of it name. And yes, it can get into an infinite loop. (In tests, the system buffer only retrieve one filename, and requery in each iteration). You can try

break > a.txt && cmd /v:on /c "for %f in (*.txt) do break > !random!.txt"

All my tests has been made on a windows 7 64bit, NTFS and FAT32 partition (this on a USB drive). No way to test other configurations. If anyone see a diferent behaviour, please comment.

For more information, ZwQueryDirectoryFile

OTHER TIPS

I don't know why, but when you write ... IN (*.txt) ... in the second for loop, it is trying to find files that are just created within the body of the loop.

To eliminate that, I would make my filter a bit more specific.

FOR %%i IN (file??.txt) DO (

I ran this and it creates only 20 files as expected.

Like adarshr said, the second FOR loop can find even the new created files.
You can avoid this by using FOR/F with a command, as the result of the dir is completely fetched before the body of the loop is executed.

...
FOR /F "delims=" %%i IN ('dir /b *.txt') DO (  
    echo.> file%%i.txt
    IF ERRORLEVEL 0 echo Successfully created file 'file%%i.txt'.  
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top