Search code examples
windowscmdfile-rename

How to recursively remove suffix from files?


I have a directory in which there are other directories, where are files with a similar ending: "* test today.cpp". I want to remove the " test today" part. How to do it? I searched the internet but none of the solutions fit.

I tried the following solutions:

powershell -C "gci | % {rni $_.Name ($_.Name -replace ' test today', '')}"
setlocal enableDelayedExpansion
for /r %%F in ("* test today.cpp") do (
  set "name=%%F"
  ren "!name!" "!name: test today=!"
)
ren "* test today.cpp" "*.cpp"
FOR /R %x IN (* test today.cpp) DO ren "%x" "*.cpp"

Solution

  • There can be used following batch file to recursively search in the current working directory for files matching the wildcard pattern * test today.cpp and rename those files with removal of the part test today.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    for /R %%I in ("* test today.cpp") do (
        set "FullName=%%I"
        set "FileName=%%~nxI"
        setlocal EnableDelayedExpansion
        ren "!FullName!" "!FileName: test today=!"
        endlocal
    )
    endlocal
    

    This batch file works even with any fully qualified file name (drive + path + name + extension) contains one or more exclamation mark because of delayed variable expansion is just enabled on doing the file renames. Read this answer for details about the commands SETLOCAL and ENDLOCAL.

    A faster solution would be:

    @echo off
    setlocal EnableExtensions EnableDelayedExpansion
    for /R %%I in ("* test today.cpp") do (
        set "FullName=%%I"
        set "FileName=%%~nxI"
        ren "!FullName!" "!FileName: test today=!"
    )
    endlocal
    

    But this solution does not work if the file name with full path assigned to the loop variable I contains one or more ! because of the exclamation mark is interpreted now as beginning/end of a delayed expanded variable reference on the two command lines with set.

    The similar code posted in the question does not work with enabled delayed variable expansion because of the command REN requires the new name without path which is not the case with the posted code in the question.

    NOTE 1: The current working directory can be any directory. It must not be the directory containing the batch file. The process starting cmd.exe by calling the Windows kernel library function CreateProcess with %SystemRoot%\System32\cmd.exe as application to run defines the current working directory. There can be used for /R "%~dp0" %%I to search recursively in the batch file directory instead of the current working directory.

    NOTE 2: FOR ignores files with hidden attribute set.

    NOTE 3: The two batch files above work on drives with NTFS, but do not work on drives with FAT32 or exFAT as file system. The two batch files below work for any file system.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    for /F "delims=" %%I in ('dir "* test today.cpp" /A-D /B /S 2^>nul') do (
        set "FullName=%%I"
        set "FileName=%%~nxI"
        setlocal EnableDelayedExpansion
        ren "!FullName!" "!FileName: test today=!"
        endlocal
    )
    endlocal
    

    The faster solution because of permanently enabled delayed variable expansion:

    @echo off
    setlocal EnableExtensions EnableDelayedExpansion
    for /F "delims=" %%I in ('dir "* test today.cpp" /A-D /B /S 2^>nul') do (
        set "FullName=%%I"
        set "FileName=%%~nxI"
        ren "!FullName!" "!FileName: test today=!"
    )
    endlocal
    

    Files with hidden attribute are renamed also by these two batch files, except /A-D is modified to /A-D-H to ignore also files with hidden attribute.

    There can be inserted %~dp0 left to * to let DIR search recursively in the batch file directory instead of the current working directory for the files to rename. %~dp0 expands to drive and path of argument 0 which is the full batch file directory path always ending with a backslash and concatenated with * for that reason without an additional backslash.

    Example for renaming the files recursively in the batch file directory independent on file system and independent on one or more ! in the fully qualified file names.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    for /F "delims=" %%I in ('dir "%~dp0* test today.cpp" /A-D /B /S 2^>nul') do (
        set "FullName=%%I"
        set "FileName=%%~nxI"
        setlocal EnableDelayedExpansion
        ren "!FullName!" "!FileName: test today=!"
        endlocal
    )
    endlocal
    

    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.

    • call /? ... explains %~dp0
    • dir /?
    • echo /?
    • endlocal /?
    • ren /?
    • set /?
    • setlocal /?

    Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /c and the command line inside ' appended as additional arguments.