How to? Wildcards as sets - looping issue with FOR and REN

Sep 27, 2012
6
0
#1
My apologies if this has been asked and answered previously; I couldn't find it with Search.

TCC 15.01.58 x64 Windows 7 [Version 6.1.7601]

I am encountering an issue when I try to rename a group of files in a subdirectory. I tried to rename the group using delayed command expansion:

ren *.pas System.%%@name[*].pas

The command ran, and kept running, forever prefixing System. to the files over and over. My understanding is that the operation should run on the set of files matching the filespec *.pas at the beginning of the command.

Example poutput, after running for a few seconds:

E:\Source\rtl\win\System.System.System.System.System.DirectDraw.pas -> E:\So
urce\rtl\win\System.System.System.System.System.System.DirectDraw.pas
1 file renamed
E:\Source\rtl\win\System.System.System.System.System.DirectInput.pas -> E:\S
ource\rtl\win\System.System.System.System.System.System.DirectInput.pas
1 file renamed


For equivalent:

for %s in (*.pas) do ren %s System.%s

exhibits the same behavior.

The for command works with CMD.

What am I missing? I think I've done this many times in the past without incident.

Thanks in advance,
Dave
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
3,724
47
Albuquerque, NM
prospero.unm.edu
#2
Renaming a file can cause it to move within the directory, causing FindFirst et al. to find it again.

There are a number of way to work around the issue. One is to use /O: to sort the set of files to be renamed, which forces FOR to generate a list before it begins the actual work of renaming them.

Another is to rename them into a different directory (yes, REN allows you to specify a path in the second wildspec), then MOVE them back home afterwards.

A third approach is to use an exclusion range to mask out those files you've already renamed. In your case, since you're adding a "SYSTEM" to the start of each filename, you might use /[!SYSTEM*] to prevent them from being found again.
 
Sep 27, 2012
6
0
#3
Charles,

Thank you for your reply. I figured this is what was happening, but didn't expect it for FOR, as the documentation states:

FOR begins by creating a set. It then executes a command for every member of set. The command can be an internal command, an alias, an external command, or a batch file. The members of set can be a list of file names, text strings, a group of numeric values, or text read from a list of files.

The FindFirst issue definitely makes sense for REN, which is what led me to try FOR.

I will keep the alternatives in mind, thanks! I would never have thought to exclude SYSTEM in the manner you describe.

Dave
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
3,724
47
Albuquerque, NM
prospero.unm.edu
#4
Aside to Rex: Would it make sense for REN to always sort before processing, e.g. /O:A by default? What would be the downside? Increased memory use and decreased speed, of course; but both would be invisible in ordinary use. Any potential compatibility issues?
 

rconn

Administrator
Staff member
May 14, 2008
10,755
97
#6
I figured this is what was happening, but didn't expect it for FOR, as the documentation states:

FOR begins by creating a set. It then executes a command for every member of set. The command can be an internal command, an alias, an external command, or a batch file. The members of set can be a list of file names, text strings, a group of numeric values, or text read from a list of files.
"set" in your example is "*", not an expanded & saved list of filenames. Which (depending on the operation) might cause an infinite loop. (The same thing can happen in CMD.)

From the help for FOR:
---------------------
When you use wildcards to specify set, FOR scans the directory and finds each file which matches the wildcard name(s) you specified. If, during the processing of the FOR command, you create a new file that could be included in set, it may or may not appear in a some later iteration of the same FOR command. Whether or not the new file appears depends on its physical location in the directory structure. For example, if you use FOR to execute a command for all .TXT files, and the command also creates one or more new .TXT files, those new files may or may not be processed during the current FOR command, depending on where they are placed in the physical structure of the directory. This is a Windows constraint over which TCC has no control. Therefore, in order to achieve consistent results you should construct FOR commands which do not create files that could become part of set for the current command.
---------------------
As Charles mentioned, there are other ways to do this; I would add include lists (@filename) as well.
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
3,724
47
Albuquerque, NM
prospero.unm.edu
#7
"set" in your example is "*", not an expanded & saved list of filenames. Which (depending on the operation) might cause an infinite loop. (The same thing can happen in CMD.)
Incidentally, this 'behavior' has as much to do with the filesystem as with the operating system. You may find that REN works one way on an NTFS hard drive, another way on a FAT32-formatted flash stick, and a third way on a network drive.
 
Sep 27, 2012
6
0
#8
Thanks for all of the replies, understood.

I learned something else today, even though it's Friday: I never knew that DO was a first-class command.