Home > Back-end >  Is it possible to remove the last two characters of all file names in a directory using command prom
Is it possible to remove the last two characters of all file names in a directory using command prom

Time:11-01

I am trying to rename files where I change the extension and remove the last two characters of the file name (excluding extension), is this possible with a windows command prompt?

For example:

INF_CAN1_Knees_Top_T209_1.OUT
INF_CAN1_Knees_Outside_T196_2.OUT

Should be renamed to:

INF_CAN1_Knees_Top_T209.txt
INF_CAN1_Knees_Outside_T196.txt

Changing the extension is easy:

rename *.OUT *.txt works.

I would think that rename *_?.OUT *.txt would work, but it does not, it changes the extension, but the _1 or _2 remains. This surprises me, because it seems that the * has a different value in the input and output.

Is it possible to do this, and why does it not work how I tried it?

CodePudding user response:

There can be used the following batch file for this file renaming task:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if exist "*!*_?.out" goto ExtendedVersion

setlocal EnableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir *_?.out /A-D-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /R "_[0123456789]\.out"') do (
    set "FileNameOut=%%~nI"
    set "FileNameNew=!FileNameOut:~0,-2!.txt"
    if not exist "!FileNameNew!" ren "!FileNameOut!%%~xI" "!FileNameNew!"
)
endlocal
goto EndBatch

:ExtendedVersion
echo INFO: Extended version required because of an OUT file with exclamation marks.
for /F "eol=| delims=" %%I in ('dir *_?.out /A-D-L /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /R "_[0123456789]\.out"') do (
    set "FileNameOut=%%~nI"
    setlocal EnableDelayedExpansion
    set "FileNameNew=!FileNameOut:~0,-2!.txt"
    if not exist "!FileNameNew!" ren "!FileNameOut!%%~xI" "!FileNameNew!"
    endlocal
)

:EndBatch
endlocal

There is defined first the required execution environment with the first two command lines.

The IF condition in the third command line quickly checks if there is any OUT file containing one or more exclamation marks in the file name. The extended version of the processing loop is required if this condition is true.

The standard version enables first required delayed expansion. Then a FOR loop is used which runs in background with Windows installed into C:\Windows:

C:\Windows\System32\cmd.exe /c dir *_?.out /A-D-L /B 2>nul | C:\Windows\System32\findstr.exe /E /I /R "_[0123456789]\.out"

The internal command DIR of cmd.exe searches

  • in the current directory as defined by the process starting cmd.exe for processing the batch file
  • for just file names because of option /A-D-L (attribute not directory and not link)
  • matching case-insensitive the wildcard pattern *_?.out in long or short 8.3 name
  • and outputs in bare format because of option /B just the file names with file extension, but without file path.

An error message output to handle STDERR (standard error) on DIR does not find any file system entry matching the criteria is suppressed by redirecting this error message to the device NUL.

Read the Microsoft documentation 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.

The output of DIR is redirected to STDIN (standard input) of FINDSTR which searches case-insensitive for lines (= long file names) ending with an underscore, a digit in range 0-9 and the file extension .out using a regular expression. FINDSTR works as filter. It filters out all *.out files of which file name is ending with just an underscore or with an underscore and a different character than a digit.

Please note that ? means any character zero OR one times!

FOR respectively cmd.exe processing the batch file captures all output written to standard output stream of in background started cmd.exe and processes it line by line after started cmd.exe closed itself after finishing executing the command DIR.

FOR with option /F is used here to get a list of file names of *_?.out files loaded into memory of cmd.exe before really doing the file renames as otherwise it could happen especially on FAT drives (FAT32, exFAT) that some OUT files are processed more than once (on rename not possible).

FOR on using option /F ignores always empty lines which is no problem here as DIR with the used options does not output empty lines.

FOR would next split up the lines into substrings using horizontal tab and normal space as string delimiters, would look next if first tab/space separated string begins with a semicolon in which case it would also ignore the entire line for further processing, and would otherwise assign just the first tab/space separated string to the specified loop variable I before running the commands in body of FOR.

The default line splitting behavior is not wanted as OUT file names can contain one or more spaces. The usage of the option delims= defines an empty list of delimiters which turns off the line splitting behavior.

It is very unusual but nevertheless possible that an OUT file name begins with ; (semicolon). Such a file name should not be ignored by FOR. The option eol=| defines a vertical bar as end of line character which no file name can contain ever. Microsoft lists the characters not allowed in a file name on Windows file systems in the documentation about Naming Files, Paths, and Namespaces.

The current file name without file extension .out is assigned first to the environment variable FileNameOut.

Next a string substitution is used to get from the string value of the environment variable FileNameOut the file name without the last two characters concatenated with the file extension .txt assigned to the environment variable FileNameNew.

If there is not already a TXT file, there is next executed the command REN to rename the *_?.out file to *.txt with the removal of the last two characters before file extension.

The command ENDLOCAL after the loop restores the previous environment before enabling delayed expansion and the command GOTO instructs the Windows Command Processor to continue processing the batch file with the command line below the label EndBatch which contains one more ENDLOCAL to restore the environment on starting the batch file processing.

The extended version is nearly the same as the standard version. The difference is that delayed variable expansion is not enabled on assigning the file name of the current *_?.out file without the file extension to the environment variable FileNameOut. That avoids interpreting the exclamation mark(s) in the file name as beginning/end of a delayed expanded variable reference resulting in a manipulation of the file name string before assigning it to the environment variable as it would happen with delayed expansion already enabled.

The extended version enables next delayed variable expansion inside the loop, does the same as the standard version and restores finally the previous environment before processing the next *_?.out file.

The extended version is slower because of the environment variables list copy and the other operations made in background by every execution of SETLOCAL as explained in full details in this answer. The command ENDLOCAL in the loop is required to avoid a stack overflow on processing lots of OUT files.

The user´s expectation on how command RENAME works with using wildcard patterns is most often wrong. If the first argument string contains wildcard pattern characters like * and ?, the wildcard pattern is used only for finding file system entries matched by the wildcard pattern. The first wildcard pattern string is not taken into account on doing the rename. For the rename matters only the second argument string. If the second argument string is a wildcard pattern, then this pattern is applied to current file/folder name to identify which characters to keep and which characters to change independent on the wildcard pattern used before to find files/folders to rename at all.

To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • ren /?
  • set /?
  • setlocal /?
  • Related