DIR filenames that contain extensions

Problem

Listing all files that have zip in the basename (before the last dot, if any) is tricky because of two reasons:

  • Windows only has two wildcards: * and ?.

    * matches any number of characters (including zero).

    ? matches exactly one character (except for the dot), unless it's the last character of the pattern, followed by a dot, only other wildcards or only other wildcards and then a dot.1

  • There are no actual extension in long filenames. The GUI might treat everything that follows the last dot as the file's extension, but that's just a convention.

    To make matters worse, . has a special meaning on the command prompt. Before LFN, every file had an extension (although it could be empty). Therefore, *.* matched all files, while * matched only files with an empty extension.

    To maintain some backward compatibility, . is ignored if it's followed only by wildcards and other dots, except if the dots are adjacent and followed by at least one wildcard or if there's no wildcard at all and at most a single asterisk before the dot.1

Examples:

  • foo?.bar will match the file foo.bar, but foo?bar won't match neither foobar nor foo.bar.

  • *, *.*, *.*., *.*.* and **. will match all files in any given folder, while *., *.. and *..* won't.

Workaround

Unless you're using the archive bit to perform incremental backups2, there's a way to display the files you're interested in (and only those), using only DIR and the ATTRIB command.

Steps:

  1. First, set the archive bit on all files that contain zip anywhere in their respective filenames:

     ATTRIB +A *zip*
    
  2. Now, unset the archive bit on all files with a zip extension:

     ATTRIB -A *.zip
    

    If you want to exclude files whose respective extensions end with zip as well (e.g., ezip), use the following command instead:

     ATTRIB -A *.*zip
    

    Since *.*zip will get tested against the 8.3 filenames as well, this will also match files whose respective extensions begin with zip (e.g., zipx), unless the 8.3 filenames aren't present or have been altered.

  3. Since the previous command unset the archive bit on files like nanozip.zip, reset those:

     ATTRIB +A *zip*.*zip
    
  4. Now, you can use the /AA switch of the DIR command to show only files with a set archive bit:

     DIR /AA *zip*
    

With the /S switch on DIR and the /S [/D] switch on ATTRIB, this even works for files in subdirectories.


1 This is intended as a list of quirks, rather than an exhaustive explanation of wildcard behavior.

2 Windows XP's NTBackup, e.g., respects the archive bit.