Search code examples
windowsfor-loopcmd

CMD FOR loop does not output the expected result


I'm learning about CMD for loops. I created a directory tree rooting in the folder C:\Users\Ahmed\Desktop\Playing_Field:

├───New folder - Copy
├───New folder - Copy (10)
├───New folder - Copy (11)
├───New folder - Copy (12)
├───New folder - Copy (13)
├───New folder - Copy (14)
├───New folder - Copy (15)
├───New folder - Copy (16)
├───New folder - Copy (17)
├───New folder - Copy (18)
├───New folder - Copy (19)
├───New folder - Copy (2)
├───New folder - Copy (20)
├───New folder - Copy (21)
├───New folder - Copy (22)
├───New folder - Copy (23)
├───New folder - Copy (24)
├───New folder - Copy (25)
├───New folder - Copy (26)
├───New folder - Copy (27)
├───New folder - Copy (28)
├───New folder - Copy (29)
├───New folder - Copy (3)
├───New folder - Copy (30)
├───New folder - Copy (31)
├───New folder - Copy (32)
├───New folder - Copy (33)
├───New folder - Copy (34)
├───New folder - Copy (35)
├───New folder - Copy (36)
├───New folder - Copy (4)
├───New folder - Copy (5)
├───New folder - Copy (6)
├───New folder - Copy (7)
├───New folder - Copy (8)
└───New folder - Copy (9)

Then I tried to filter through them using this command:

for /d %n in (C:\Users\Ahmed\Desktop\Playing_Field\*3*) do @echo "%n"

The output was:

"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (10)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (20)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (16)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (13)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (23)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (3)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (30)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (31)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (32)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (33)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (34)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (35)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (36)"
"C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (2)"

Why are there some folders in the output that do not contain 3 in their names, such as New folder - Copy (2)?


Solution

  • Modern Windows systems still support so-called short file names and even may have them enabled by default, besides the usual long files names. These short file names, also called 8.3 names (because of up to 8 characters for the base name and up to 3 characters for the extension), originate from MS-DOS and pre-Windows 95 systems, and are automatically generated in the background1.

    To display such short file names, use the dir command, together with its /X option:

    >>> dir /X /-C /A:D-H-S "%SystemDrive%\Progr*"
     Volume in drive C has no label.
     Volume Serial Number is 0000-0000
    
    2022/07/10  19:00    <DIR>          PROGRA~1     Program Files
    2022/07/10  19:00    <DIR>          PROGRA~2     Program Files (x86)
                   0 File(s)              0 bytes
                   2 Dir(s)    412316860416 bytes free
    

    Now wildcards (like * and ?) match against both the long and the short file names:

    >>> dir /X /-C /A:D-H-S "%SystemDrive%\Pro*1"
     Volume in drive C has no label.
     Volume Serial Number is 0000-0000
    
    2022/07/10  19:00    <DIR>          PROGRA~1     Program Files
                   0 File(s)              0 bytes
                   1 Dir(s)    412316860416 bytes free
    

    To always match against the long file names, use find or findstr to post-filter the returned items by dir /B:

    >>> dir /B /A:D-H-S "%SystemDrive%\Progr*" | find /I "Program"
    Program Files
    
    >>> dir /B /A:D-H-S "%SystemDrive%\Progr*" | findstr /I /B "Program"
    Program Files
    

    Or, applied to your code, using for /F to capture the result:

    >>> for /F "eol=| delims=" %I in ('dir /B /A:D-H-S /O:N "%UserProfile%\Desktop\Playing_Field\*3*" ^| find /I "3"') do @echo "%I"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (13)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (23)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (3)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (30)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (31)"
    ...
    
    >>> for /F "eol=| delims=" %I in ('dir /B /A:D-H-S /O:N "%UserProfile%\Desktop\Playing_Field\*3*" ^| findstr /I "3"') do @echo "%I"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (13)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (23)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (3)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (30)"
    "C:\Users\Ahmed\Desktop\Playing_Field\New folder - Copy (31)"
    ...
    

    1) Note that disabling the short file names will not remove already generated such names.