Does anyone know how to replace first space in a file name by a text like _TEMP-
after the first 8 characters of the file name?
Also I was hoping to write a batch file that can change multiple files in a directory with similar file name structure.
For example:
Before: 12345678 Hello World.txt
After: 12345678_TEMP-Hello World.txt
Here is a simple code demonstrating usage of FOR for this task:
@echo off
set "FileName=12345678 Hello World.txt"
for /F "tokens=1*" %%I in ("%FileName%") do echo ren "%FileName%" "%%I_TEMP-%%J"
set "FileName="
echo/
pause
The file name is assigned here to an environment variable.
The command FOR with option /F
splits the file name string specified in double quotes up into substrings using the default delimiters space and horizontal tab.
With tokens=1*
is defined that first space/tab delimited string is assigned to specified loop variable I
. The asterisk is responsible for not further splitting up on spaces/tabs after first string and instead assign everything after space(s)/tab(s) after first string to next loop variable which is according to ASCII table the loop variable J
. So for this example I
gets assigned 12345678
and J
gets assigned Hello World.txt
The command to execute is here ECHO which prints the command line for renaming the file which would be executed without echo
.
Another batch code which renames all non hidden files in current directory with a space in file name not containing already _TEMP-
in file name:
@echo off
for /F "eol=| delims=" %%# in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do (
for /F "tokens=1*" %%I in ("%%#") do ren "%%#" "%%I_TEMP-%%J"
)
The outer FOR executes in a separate command process started with cmd.exe /C
in background the command line:
dir "* *" /A-D-H /B 2>nul | C:\Windows\System32\findstr.exe /L /V /C:_TEMP- 2>nul
DIR searches in current directory because of /A-D-H
(attribute not directory and not hidden) just for non hidden files matching the wildcard pattern * *
and outputs just the found file names because of /B
(bare format). An error message in case of no file matching these criteria is suppressed by redirecting the error message written to handle STDERR to the device NUL.
The file names output by DIR to handle STDOUT are redirected to STDIN of command FINDSTR which searches in the list of file names case-sensitive and literally for the string _TEMP-
. But output are not the lines containing this string, but the inverted result because of /V
. So output are by FINDSTR to handle STDOUT all lines not containing the string _TEMP-
. A possible error message output by FINDSTR to handle STDERR is suppressed by redirecting it to device NUL.
The outer FOR captures the output to STDOUT of background command process and then processes the captured output line by line. It is very important here to process a captured list of file names because the found files to modify in current directory are renamed by the command inside the FOR loop. Otherwise on using FOR itself to find files matching wildcard pattern * *
it could happen that a renamed file is processed multiple times or some files are skipped because of list of files in current directory changes during loop execution.
Empty lines are always ignored by FOR, but the list of file names does not contain empty lines.
for /F
would also ignore lines starting with a semicolon by default. This behavior is changed by specifying eol=|
to skip lines starting with a vertical bar. File names can begin with a semicolon, but file names cannot contain a vertical bar. So it is made sure not skipping any file name with eol=|
.
for /F
with default options would split a line (file name) up on spaces/tabs and would assign just first substring to specified loop variable #
. This behavior is not good here because the complete file name from filtered output of DIR is needed for the file renaming task. For that reason delims=
is used specifying an empty list of delimiters resulting in no splitting up the line (file name) into substrings (tokens).
It could be that a file is named for example 12345678 Hello World.txt
with multiple spaces in series in file name. This is the reason for first getting assigned to loop variable #
the complete file name as found by DIR in current directory.
The file name is split up into two substrings as explained above and then renamed which is successful if there is not already a file or folder with new name in current directory and the file to rename is not opened currently by an application with sharing access denied.
The batch file above could be coded also with a single command line in batch file:
@for /F "eol=| tokens=1*" %%I in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do @ren "%%I %%J" "%%I_TEMP-%%J"
Or the single command line is really executed directly in a command prompt window as follows with just one percent sign on referencing the loop variables I
and J
:
for /F "eol=| tokens=1*" %I in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /V /C:_TEMP- 2^>nul') do @ren "%I %J" "%I_TEMP-%J"
But this single command line version works only for files with always a single space character between first part and remaining part of file name, i.e. it works for 12345678 Hello World.txt
but does not work for 12345678 Hello World.txt
.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
findstr /?
for /?
pause /?
ren /?
set /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul
and |
. The redirection operators >
and |
must be escaped with caret character ^
on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.