change file extension in batch

elbarna picture elbarna · May 15, 2016 · Viewed 9.2k times · Source

Simple question. IMDU command do

imdu /b file.imd file.raw

and convert the file.imd on file.raw

I have a lot of .imd so I need a batch. I have tried:

for %%x in (*.imd) do imdu /b %%x %%~nx.raw

But it doesn't work and creates a file called %%.raw

I need a batch which will remove the extension imd and replace it with raw. How can I do that?

Answer

Mofi picture Mofi · May 15, 2016

Open a command prompt window, run for /? and read the output help carefully and completely.

There is explained %~xI – only file extension of %I – and %~nI – only file name of %I – and %~nxIfile name with extension of %I. Please note that it does not matter if the string assigned to case-sensitive loop variable I is really a file or a folder which really exists or does not exist at all. In fact it can be any string.

The file name referenced with %~nI is the string after last backslash up to last dot or end of string. It can be an empty string if the string assigned to loop variable ends with a backslash, i.e. is a folder path, or name of file starts with a dot and has no real file extension like hidden files on UNIX/MAC are often named.

The file extension referenced with %~xI is everything from last dot after last backlash to end of string assigned to loop variable. So %~xI references the file name of a file with a name like .htaccess and not %~nI which is in this special case an empty string. A file named .htaccess is on UNIX/MAC a file with real name being htaccess and . at beginning of file name makes this file hidden on UNIX/MAC file systems.

Please note that loop variables are case-sensitive while the modifiers like n, x, f, ... are not case-sensitive. So %~NXI is identical to %~nxI. It is in general better readable to use a loop variable in upper case and the modifiers in lower case.

It can be confusing for readers and in some special cases also for cmd.exe what is meant on using as loop variable a character which is also a modifier, for example on running in a cmd window the command line:

for %f in ("1. " "2. " "3. ") do @echo %~ffile

I is not a modifier and so the wrong output by the command line above can be avoided using %I instead of %f as it can be seen on running in a Windows command prompt window:

for %I in ("1. " "2. " "3. ") do @echo %~Ifile

Now it is clear that %~ff was interpreted as reference to full qualified file name of string assigned to loop variable f while %~I is interpreted as referencing the string assigned to loop variable I with double quotes removed.

So I recommend to avoid one of these characters ADFNPSTXZadfnpstxz as loop variable or be at least careful on using them.

For all that reasons it is better to use in batch file on which the percent sign must be doubled the following command line:

for %%I in (*.imd) do imdu.exe /b "%%I" "%%~nI.raw"

For such simple loops it is also possible and good practice to use an ASCII character not being a letter or digit having no special meaning for Windows command processor like:

for %%# in (*.imd) do imdu.exe /b "%%#" "%%~n#.raw"

It is easier to search in batch file for all occurrences of # than for all occurrences of a letter existing also many times in other strings. The character $ is also very good as loop variable because it has also no special meaning and does usually not exist in other strings in a batch file.

Don't forget the double quotes around the file names as files could contain spaces or round brackets or ampersands in their file names which require double quotes around file names. Command FOR holds in this use case a file name always without surrounding double quotes in loop variable.

One more hint:

The usage of FOR to process files or folders matching a wildcard pattern which are renamed, moved or deleted by executed command line(s) on FOR iterations is problematic on FAT32 and exFAT drives because of list of directory entry changes while FOR accesses this list during loop iterations.

For example the command line below in a batch file with current directory being on a FAT32 or exFAT drive can result in a temporary file being renamed more than once.

for %%# in (*.tmp) do ren "%%#" "%%~n#_1.tmp"

In such cases it is better to use in the batch file command DIR to get a list of file names captured by FOR which processes now a list of file names not being modified by the command line(s) executed by FOR on each file name as shown below.

for /F "eol=| delims=" %%# in ('dir *.tmp /A-D /B /ON 2^>nul') do ren "%%#" "%%~n#_1.tmp"