6

On Windows 7, I have a directory containing the following four files:

  • xxx.txt
  • xxx.txt2
  • xxx2.txt
  • xxx2.txt2

With the file have more than 3 character as a file extension, the behavior of the wildcard * seems odd:

dir *.txt

10/13/2014  04:14 PM                 6 xxx.txt
10/13/2014  04:17 PM                 6 xxx2.txt
10/13/2014  04:17 PM                 6 xxx2.txt2
10/13/2014  04:14 PM                 6 xxx.txt2
           4 File(s)             24 bytes
           0 Dir(s)   6,660,980,736 bytes free

I would expect to see only the two files with txt extension and not the ones with txt2 (like it would on a Linux machine). Does MS-DOS ignore the truncate the file extension to 3 characters or does it add automatically another wildcard at the end? If I want to delete only the files with txt extension and not the one with txt2, which command should I use? Thanks

2

4 Answers 4

7

You're not using MS-DOS; it did not even allow file extensions longer than 3 characters. You're using the Windows command line – the cmd.exe shell, specifically.

But Windows indeed tries hard to remain compatible with programs from that era. So, up until Windows 8 (or something like that), all files with longer extensions have an alias that has the extension truncated, along with the name itself.

If you run dir /x, you'll likely see that each file has a "short name" assigned to it, which is limited to 8+3 characters, just like in MS-DOS and 16-bit Windows.

These names are there in case the user wanted to, let's say, upgrade to Windows 95 and still access their files through programs originally written for Windows 3.1 – so running a 16-bit program wouldn't crash, but would merely show C:\PROGRA~1 and C:\MYDOCU~1\CALENDAR.TXT in place of C:\Program Files and C:\My Documents\Calendar.txt.

(And yes, some people did actually use old 16-bit software even in Windows XP/Vista days... I'm pretty sure Windows 8 turn off the "short names" by default, however. This might be why @EBGreen isn't seeing the same 'problem'...)


Another thing to consider is that the old Windows shell, cmd.exe, has grown quite a few quirks and compatibility fixes in itself. For example, due to the way MS-DOS matched filenames, dir .txt meant the same as dir *.txt, even though it wasn't intentional. But people got used to the shorter syntax, and even though the Windows operating system itself doesn't treat .txt as a wildcard anymore, cmd.exe still accepts that syntax. (The dir command isn't a program on its own, but built into the shell.)

(Similarly, in the linked article, another wildcard quirk is described – Windows filenames can have no extension at all, but people are really used to typing *.*, therefore it means the same thing as * and the lone dot is ignored.)

5
  • Just to be clear, I do see the same behavior as the OP. I will also add that trying to use the 8.3 name of the files would still not work since the first part of the file name gets changed to do the 8.3 name and the extension would be changed to .txt in this example so trying to wildcard on the extension still would not work even using dir /x
    – EBGreen
    Commented Oct 13, 2014 at 14:56
  • dir /x doesn't use the short names, it merely shows them. The short names are used automatically in any situation where the long names work. That is, whenever a program asks the OS to match wildcards, the OS will consider both the short and long name, and the short one will match. Commented Oct 13, 2014 at 15:04
  • I was aware of the short name (and use it sometimes for programs that do not accept path names containing spaces) but I did not know wildcards would match those as well. Would there be an alternative method to remove all files with a given extension and ignore the other ones? I'm thinking something like "dir|findstr \....$|del"?
    – tristof
    Commented Oct 14, 2014 at 9:43
  • 1
    @tristof: Yes, or perhaps for %f in (*) if "%~xf"==".txt" ..., as merely iterating over the directory will only return long names. Commented Oct 14, 2014 at 9:53
  • 1
    The question says, “If I want to delete only the files with txt extension and not the one with txt2, which command should I use?”  My eyesight is failing; I don’t see where you answered that question (you explain why the OP has the problem they have, but not how to fix it) except in that last comment.  Can you put the answer into the answer, please?  (See also DOS — moving specific .xml file extension.) Commented Oct 5, 2018 at 19:17
3

I can't tell you why it works that way. It is quite odd. What I can tell you is that Powershell (which you should have on the machine) works the way that you expect. In powershell:

PS I:\temp\test> ls


    Directory: I:\temp\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/13/2014   9:29 AM          3 bar.txt
-a---        10/13/2014   9:29 AM          3 bar.txt2
-a---        10/13/2014   9:29 AM          3 foo.txt
-a---        10/13/2014   9:29 AM          3 foo.txt2

PS I:\temp\test> ls *.txt


    Directory: I:\temp\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/13/2014   9:29 AM          3 bar.txt
-a---        10/13/2014   9:29 AM          3 foo.txt
2

grawity correctly identified that the behavior stems from short file names. Filemasks are compared to both the long and short names.

The full rules for how wild cards are matched against file names is available in the "sourceMask" section of How does the Windows RENAME command interpret wildcards?

You can get your desired DIR result by piping to FINDSTR:

dir *.txt* | findstr /vrix "[0-9].*\.txt[^.][^.]*"
2

As others have pointed out, this is about short file names generation. But note that this is not system-wide settings. It can be different per volume. I've noticed on my machine that the behavior varies between drives. And indeed, my C: drive has short name generation on, while the D: drive has it off. You can check it with fsutil 8dot3name command (as Admin).

C:\>dir *.txt
 Volume in drive C is Windows
 Volume Serial Number is EC1B-17C1
 
 Directory of C:\
 
28.08.2023  10:25                10              foo.txt
28.08.2023  10:25                11 FOO~1.TXT    foo.txt2
               2 File(s)             21 bytes
               0 Dir(s)  36 329 230 336 bytes free
               
C:\>fsutil 8dot3name query C:
The volume state is: 0 (8dot3 name creation is enabled).
The registry state is: 2 (Per volume setting - the default).

Based on the above settings, 8dot3 name creation is enabled on C:

C:\>D:

D:\>dir *.txt
 Volume in drive D is Data
 Volume Serial Number is EFFC-CC70
 
 Directory of D:\
 
28.08.2023  10:25                10              foo.txt
               1 File(s)             10 bytes
               0 Dir(s)  309 316 231 168 bytes free
               
D:\>fsutil 8dot3name query D:
The volume state is: 1 (8dot3 name creation is disabled).
The registry state is: 2 (Per volume setting - the default).

Based on the above settings, 8dot3 name creation is disabled on D:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .