SS64 Discussion Forum

You are not logged in.

#1 2010-01-14 08:12:17

anandr
8086
From: Ukraine
Registered: 2007-10-20
Posts: 11

Strange behaviour of file mask in DIR command

Hi all

I have a program that creates series of images named, say, "Photo1.bmp", "Photo2.bmp", etc.
When number of files is more than 10 or 100, there is an issue with sorting these files, because
"Photo10.bmp" appears after "Photo1.bmp" and before "Photo2.bmp":

C:\TEMP\TEST>dir /b

Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo101.bmp
Photo102.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo3.bmp
Photo4.bmp
Photo5.bmp
Photo6.bmp
Photo7.bmp
Photo8.bmp
Photo9.bmp

The same sorting issue arises in the windows explorer.

I need to rename these files adding padding zeros like this (more padding zeros is also OK):

Photo001.bmp
Photo002.bmp
Photo003.bmp
Photo004.bmp
Photo005.bmp
Photo006.bmp
Photo007.bmp
Photo008.bmp
Photo009.bmp
Photo010.bmp
Photo011.bmp
Photo012.bmp
Photo013.bmp
Photo100.bmp
Photo101.bmp
Photo102.bmp

I tried to write a batch file that scans sequentially through one-, two-, three-digit files and adds padding zeroes.
But I stuck with unexpected behavior of the file mask in DIR command.
To be short here is a batch file that presents it:

@Echo off
rem    % 1    file prefix
rem    % 2    file extension
Echo One-digit files:
FOR /F %%i IN ('dir /b %~1?.%~2') DO @(    Echo %%i    )
Echo.
Echo Two-digit files:
FOR /F %%i IN ('dir /b %~1??.%~2') DO @(    Echo %%i    )
Echo.
Echo Three-digit files:
FOR /F %%i IN ('dir /b %~1???.%~2') DO @(    Echo %%i    )
Echo.

When I run it like this

C:\TEMP\TEST>RenameFilesTo_6digits.cmd Photo bmp

I have the following output:

One-digit files:
Photo1.bmp
Photo2.bmp
Photo3.bmp
Photo4.bmp
Photo5.bmp
Photo6.bmp
Photo7.bmp
Photo8.bmp
Photo9.bmp

Two-digit files:
Photo1.bmp
Photo10.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo3.bmp
Photo4.bmp
Photo5.bmp
Photo6.bmp
Photo7.bmp
Photo8.bmp
Photo9.bmp

Three-digit files:
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo101.bmp
Photo102.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo3.bmp
Photo4.bmp
Photo5.bmp
Photo6.bmp
Photo7.bmp
Photo8.bmp
Photo9.bmp

I can not understand, why dir /b Photo?.bmp matches "Photo1.bmp" ... "Photo9.bmp", but
dir /b Photo??.bmp matches not just two-digit files, but also one-digit ones: "Photo1.bmp" ... "Photo9.bmp"?

Does anybody have an explanation of this?

I'm using WinXP SP2 PRO

C:\TEMP\TEST>ver
Microsoft Windows XP [Version 5.1.2600]

P.S.
It would be nice if someone can suggest a better idea how to rename such sequence of files.
By the way, sorting them in creation/modification order do not always work,
because some of them should be processed by other programs,
so their creation/modification time is altered.

Last edited by anandr (2010-01-14 09:08:31)


Everything will be OK at the end. If it is not OK -- it is not the end.

Offline

#2 2010-01-14 13:14:57

bluesxman
Sun Fire
From: Leeds, UK
Registered: 2006-12-29
Posts: 701

Re: Strange behaviour of file mask in DIR command

Yeah I don't think you will get around that easily, so a different approach is probably advisable.

How about something like this instead?

@echo off

set "prefix=%~1"
set "ext=%~2"
set "pad.length=6"
set "pad="

for /l %%a in (0,1,%pad.length%) do call set "pad=%%pad%%0"

for /f "usebackq tokens=*" %%a in (`dir /b "%prefix%*.%ext%"`) do (

    set "number=%%~na"
    call set "number=%pad%%%number:%prefix%=%%"
    call set "newname=%prefix%%%number:~-%pad.length%%%%%~xa
    call rename "%%~a" "%%newname%%"

)


pause

Last edited by bluesxman (2010-01-14 16:10:34)

Offline

#3 2010-01-15 08:10:17

Drewfus
8088
From: Australia
Registered: 2010-01-10
Posts: 31

Re: Strange behaviour of file mask in DIR command

anandr,
try this;

@echo off
setlocal
for /F %%A in ('dir /B Photo*.bmp') do call :bmp %%~nA
goto :eof

:bmp
set bmp=%*
set bmp=%bmp:Photo=%
set bmp=000%bmp%
ren %*.bmp Photo%bmp:~-4%.bmp
goto :eof

Now sorting the files will work as you want...

dir /B *.bmp | sort

Offline

#4 2010-01-15 09:01:30

bluesxman
Sun Fire
From: Leeds, UK
Registered: 2006-12-29
Posts: 701

Re: Strange behaviour of file mask in DIR command

Er Drewfus, you've just used the same basic method as I suggested, but implemented it in a less flexible and robust way hmm

Offline

#5 2010-01-15 10:36:32

anandr
8086
From: Ukraine
Registered: 2007-10-20
Posts: 11

Re: Strange behaviour of file mask in DIR command

Thank you both, bluesxman and Drewfus, for your replies.
I agree with bluesxman that his solution is more flexible.

Still, what's wrong with the file mask in DIR command?
Is this another example how MS makes documentation that reflects how things should work instead of how things really work?

Just one more question concerning the script: sometimes I have files named like this: "1.jpg", "2.jpg", ..., "10.jpg", "11.jpg", "1.jpg".
In this case file prefix is empty.
I tried to handle this and here is a script which satisfies me by 99.9%.
I'm only 99.9% satisfied with it, because I can not figure out how to treat "0.jpg" file in such sequence, so I'm checking for it presence manually, not through the main loop.
May be someone has an idea how to do this in nicer way?

@echo off
@setlocal enabledelayedexpansion

set "Pad.Length.Default=6"

:: no parameters at all -- print usage and exit
if  [%~1%~2%~3] EQU [] goto PrintUsage

:: one parameter only -- print usage and exit
if  [%~2%~3] EQU [] goto PrintUsage

set "Prefix=%~1"
set "Ext=%~2"
set "Pad.Length=%~3"

if  [%Pad.Length%] EQU [] call set "Pad.Length=%%Pad.Length.Default%%"

set "Pad="
for /l %%a in (0,1,%Pad.Length%) do call set "Pad=%%Pad%%0"

::DEBUG: Echo                 Pad = "%Pad%"
::DEBUG: Echo              Prefix = "%Prefix%"
::DEBUG: Echo                 Ext = "%Ext%"
::DEBUG: Echo  Pad.Length.Default = "%Pad.Length.Default%"
::DEBUG: Echo          Pad.Length = "%Pad.Length%"

if  [%Prefix%]     EQU [] goto ProcessEmptyPrefix

:ProcessNonEmptyPrefix
for /f "usebackq tokens=*" %%a in (`dir /b "%Prefix%*.%Ext%"`) do (
    set "Number=%%~na"
    call set "Number=%Pad%%%Number:%Prefix%=%%"
    call set "NewName=%Prefix%%%Number:~-%Pad.Length%%%%%~xa"
    call Echo renaming    "%%~a"    "%%NewName%%"
    call rename "%%~a" "%%NewName%%"
)
goto :EOF

:ProcessEmptyPrefix
:: Currently I have no idea how to handle "0.%Ext%" file automatically, so
IF exist "0.%Ext%" (
        call set "Number=%Pad%"
        call set "NewName=%%Number:~-%Pad.Length%%%.%%Ext%%"
        call Echo renaming    "0.%%Ext%%"    "%%NewName%%"
        call rename "0.%%Ext%%" "%%NewName%%"
)
for /f "usebackq tokens=*" %%a in (`dir /b "*.%Ext%"`) do (
    set "Number=%%~na"
    SET /A NextNumber=1 + Number
    SET /A AnotherNumber=NextNumber + Number
:: Uncomment next line to see which files are accepted
::DEBUG:     Echo Number = "!Number!"; NextNumber = "!NextNumber!"; AnotherNumber = "!AnotherNumber!"; If NextNumber ^< AnotherNumber -- then we have number-named file
    IF  !NextNumber! LSS !AnotherNumber! (
        call set "Number=%Pad%%%Number%%"
        call set "NewName=%%Number:~-%Pad.Length%%%%%~xa"
        call Echo renaming    "%%~a"    "%%NewName%%"
        call rename "%%~a" "%%NewName%%"
    )
)

:PrintUsage
Echo.
Echo This script scans current directory for files named "<FilePrefix>#.<Extension>" (# is a number)
Echo and adds padding zeros to the number.
Echo.
Echo Usage:
Echo     %~n0 ^<FilePrefix^> ^<Extension^> [^<PaddingLength^>]
Echo.
Echo If ^<PaddingLength^> is omitted, then default value "%Pad.Length.Default%" is used.
Echo.
Echo To process files without prefix (like "1.jpg", "2.jpg", "13.jpg", etc.), run the script like this:
Echo     %~n0 "" ^<Extension^> [^<PaddingLength^>]
goto :EOF

Last edited by anandr (2010-01-15 10:46:28)


Everything will be OK at the end. If it is not OK -- it is not the end.

Offline

#6 2010-01-15 11:33:38

bluesxman
Sun Fire
From: Leeds, UK
Registered: 2006-12-29
Posts: 701

Re: Strange behaviour of file mask in DIR command

Amending my own code (shouldn't be too difficult to shoehorn this back into yours):

@echo off

set "prefix=%~1"
set "ext=%~2"
set "pad.length=6"
set "pad="

for /l %%a in (0,1,%pad.length%) do call set "pad=%%pad%%0"

for /f "usebackq tokens=*" %%a in (`dir /b "%prefix%*.%ext%"`) do (

    set "number=%%~na"
    REM pad to 6 characters
    if defined prefix (call set "number=%pad%%%number:%prefix%=%%") ELSE (call set "number=%pad%%%number%%")
    call set "newname=%prefix%%%number:~-%pad.length%%%%%~xa
    call echo:rename "%%~a" "%%newname%%"

)

pause

You'd still have to specify a blank parameter with "", as you already instruct the user.

As for "dir" behaviour, I can see what it's doing -- it's treating "?" as zero or one occurrence of any character, in much the same way that "*" matches zero or any number of occurrences of any character:

D:\My Documents\Scripts\ss64>dir Photo?.bmp
 Volume in drive D is Data
 Volume Serial Number is EF78-7FFA

 Directory of D:\My Documents\Scripts\ss64

15/01/2010  16:29                 0 Photo.bmp
15/01/2010  16:29                 0 Photo1.bmp
               2 File(s)              0 bytes
               0 Dir(s)  10,290,286,592 bytes free

D:\My Documents\Scripts\ss64>dir Photo*.bmp
 Volume in drive D is Data
 Volume Serial Number is EF78-7FFA

 Directory of D:\My Documents\Scripts\ss64

15/01/2010  16:29                 0 Photo.bmp
15/01/2010  16:29                 0 Photo1.bmp
15/01/2010  16:29                 0 Photo10.bmp
               2 File(s)              0 bytes
               0 Dir(s)  10,290,286,592 bytes free

D:\My Documents\Scripts\ss64>

Offline

#7 2010-01-15 11:38:44

avery_larry
IA-32
Registered: 2007-07-11
Posts: 250

Re: Strange behaviour of file mask in DIR command

? wildcard doesn't always work like expected.  It has quirks:

http://ss64.com/nt/syntax-wildcards.html

Offline

#8 2010-01-15 12:52:46

anandr
8086
From: Ukraine
Registered: 2007-10-20
Posts: 11

Re: Strange behaviour of file mask in DIR command

Thank you for the suggestion, bluesxman. I really like it clap

avery_larry wrote:

? wildcard doesn't always work like expected.  It has quirks:
http://ss64.com/nt/syntax-wildcards.html

It seems that it has not just quirks, but QUIRKS.

First I create several files with this batch file:

Copy %0 Photo0.bmp
Copy %0 Photo1.bmp
Copy %0 Photo2.bmp
Copy %0 Photo3.bmp
Copy %0 Photo10.bmp
Copy %0 Photo11.bmp
Copy %0 Photo12.bmp
Copy %0 Photo13.bmp
Copy %0 Photo100.bmp
Copy %0 Photo101.bmp
Copy %0 Photo102.bmp
Copy %0 Photo103.bmp
Copy %0 Photo1000.bmp
Copy %0 Photo1001.bmp
Copy %0 Photo1002.bmp
Copy %0 Photo1003.bmp
Copy %0 Photo10000.bmp
Copy %0 Photo10001.bmp
Copy %0 Photo10002.bmp
Copy %0 Photo10003.bmp
Copy %0 Photo100000.bmp
Copy %0 Photo100001.bmp
Copy %0 Photo100002.bmp
Copy %0 Photo100003.bmp

Copy %0 Photo0_Suffix.bmp
Copy %0 Photo1_Suffix.bmp
Copy %0 Photo2_Suffix.bmp
Copy %0 Photo3_Suffix.bmp
Copy %0 Photo10_Suffix.bmp
Copy %0 Photo11_Suffix.bmp
Copy %0 Photo12_Suffix.bmp
Copy %0 Photo13_Suffix.bmp
Copy %0 Photo100_Suffix.bmp
Copy %0 Photo101_Suffix.bmp
Copy %0 Photo102_Suffix.bmp
Copy %0 Photo103_Suffix.bmp
Copy %0 Photo1000_Suffix.bmp
Copy %0 Photo1001_Suffix.bmp
Copy %0 Photo1002_Suffix.bmp
Copy %0 Photo1003_Suffix.bmp
Copy %0 Photo10000_Suffix.bmp
Copy %0 Photo10001_Suffix.bmp
Copy %0 Photo10002_Suffix.bmp
Copy %0 Photo10003_Suffix.bmp
Copy %0 Photo100000_Suffix.bmp
Copy %0 Photo100001_Suffix.bmp
Copy %0 Photo100002_Suffix.bmp
Copy %0 Photo100003_Suffix.bmp

Then

dir *.bmp /o:n /b

Produces this:

Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo1_Suffix.bmp
Photo10.bmp
Photo10_Suffix.bmp
Photo100.bmp
Photo100_Suffix.bmp
Photo1000.bmp
Photo1000_Suffix.bmp
Photo10000.bmp
Photo10000_Suffix.bmp
Photo100000.bmp
Photo100000_Suffix.bmp
Photo100001.bmp
Photo100001_Suffix.bmp
Photo100002.bmp
Photo100002_Suffix.bmp
Photo100003.bmp
Photo100003_Suffix.bmp
Photo10001.bmp
Photo10001_Suffix.bmp
Photo10002.bmp
Photo10002_Suffix.bmp
Photo10003.bmp
Photo10003_Suffix.bmp
Photo1001.bmp
Photo1001_Suffix.bmp
Photo1002.bmp
Photo1002_Suffix.bmp
Photo1003.bmp
Photo1003_Suffix.bmp
Photo101.bmp
Photo101_Suffix.bmp
Photo102.bmp
Photo102_Suffix.bmp
Photo103.bmp
Photo103_Suffix.bmp
Photo11.bmp
Photo11_Suffix.bmp
Photo12.bmp
Photo12_Suffix.bmp
Photo13.bmp
Photo13_Suffix.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

Then I execute another batch file testing ? wildcard:

@Echo off

Echo.
Echo 1-digit files
Echo =============
dir Photo?.bmp /O:N /B
Echo.
dir Photo?_Suffix.bmp /O:N /B

Echo.
Echo 2-digit files
Echo =============
dir Photo??.bmp /O:N /B
Echo.
dir Photo??_Suffix.bmp /O:N /B

Echo.
Echo 3-digit files
Echo =============
dir Photo???.bmp /O:N /B
Echo.
dir Photo???_Suffix.bmp /O:N /B

Echo.
Echo 4-digit files
Echo =============
dir Photo????.bmp /O:N /B
Echo.
dir Photo????_Suffix.bmp /O:N /B

Echo.
Echo 5-digit files
Echo =============
dir Photo?????.bmp /O:N /B
Echo.
dir Photo?????_Suffix.bmp /O:N /B

Echo.
Echo 6-digit files
Echo =============
dir Photo??????.bmp /O:N /B
Echo.
dir Photo??????_Suffix.bmp /O:N /B

Echo.
Echo 7-digit files
Echo =============
dir Photo???????.bmp /O:N /B
Echo.
dir Photo???????_Suffix.bmp /O:N /B

This is what I see:

1-digit files
=============
Photo0.bmp
Photo1.bmp
Photo2.bmp
Photo3.bmp

Photo0_Suffix.bmp
Photo1_Suffix.bmp
Photo2_Suffix.bmp
Photo3_Suffix.bmp

2-digit files
=============
Photo0.bmp
Photo1.bmp
Photo10.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo3.bmp

Photo10_Suffix.bmp
Photo11_Suffix.bmp
Photo12_Suffix.bmp
Photo13_Suffix.bmp

3-digit files
=============
Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo1000.bmp
Photo1001.bmp
Photo1002.bmp
Photo1003.bmp
Photo101.bmp
Photo102.bmp
Photo103.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

Photo100_Suffix.bmp
Photo101_Suffix.bmp
Photo102_Suffix.bmp
Photo103_Suffix.bmp

4-digit files
=============
Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo1000.bmp
Photo1001.bmp
Photo1002.bmp
Photo1003.bmp
Photo101.bmp
Photo102.bmp
Photo103.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

Photo1000_Suffix.bmp
Photo1001_Suffix.bmp
Photo1002_Suffix.bmp
Photo1003_Suffix.bmp

5-digit files
=============
Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo1000.bmp
Photo10000.bmp
Photo10001.bmp
Photo10002.bmp
Photo10003.bmp
Photo1001.bmp
Photo1002.bmp
Photo1003.bmp
Photo101.bmp
Photo102.bmp
Photo103.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

Photo10000_Suffix.bmp
Photo10001_Suffix.bmp
Photo10002_Suffix.bmp
Photo10003_Suffix.bmp

6-digit files
=============
Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo1000.bmp
Photo10000.bmp
Photo100000.bmp
Photo100001.bmp
Photo100002.bmp
Photo100003.bmp
Photo10001.bmp
Photo10002.bmp
Photo10003.bmp
Photo1001.bmp
Photo1002.bmp
Photo1003.bmp
Photo101.bmp
Photo102.bmp
Photo103.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

Photo100000_Suffix.bmp
Photo100001_Suffix.bmp
Photo100002_Suffix.bmp
Photo100003_Suffix.bmp

7-digit files
=============
Photo0.bmp
Photo0_Suffix.bmp
Photo1.bmp
Photo10.bmp
Photo100.bmp
Photo1000.bmp
Photo10000.bmp
Photo100000.bmp
Photo100001.bmp
Photo100002.bmp
Photo100003.bmp
Photo10001.bmp
Photo10002.bmp
Photo10003.bmp
Photo1001.bmp
Photo1002.bmp
Photo1003.bmp
Photo101.bmp
Photo102.bmp
Photo103.bmp
Photo11.bmp
Photo12.bmp
Photo13.bmp
Photo2.bmp
Photo2_Suffix.bmp
Photo3.bmp
Photo3_Suffix.bmp

File Not Found

It makes me really mad to see "Photo1000.bmp" among "3-digit files".
I can not understand how

dir Photo???.bmp /O:N /B

could match "Photo1000.bmp" file.

Anyway, as one can see ? works OK if it is not at the end of file name.
Only now I fully understand full meaning of this phrase (http://ss64.com/nt/syntax-wildcards.html):

The ? wildcard will match a single character (or a NULL at the end of a filename)

The case is closed. Thanks everyone for their attention and assistance.

Perhaps it might be a good idea to expand description of the ? wildcard a little bit with few more examples like the ones above.

Last edited by anandr (2010-01-15 12:56:46)


Everything will be OK at the end. If it is not OK -- it is not the end.

Offline

Board footer

Powered by FluxBB