windowsbatch-filerename

How to make a batch script remove exclamation marks "!" from a file name?


I want to remove exclamation marks from file names on Windows 10/11 with a batch script.

I have a folder named "Input" in the same directory as the batch file, and i simply want to have the batch file look inside the Input folder for files with exclamation marks in the file name, and then remove any exclamation marks.

So for example:

this!_is!_an!_example!!!.txt

Would be renamed to:

this_is_an_example.txt

The below batch script will remove the character "Â". However, if i change it to "!" it will no longer work, probably because of enabledelayedexpansion which has trouble with exclamation marks:

@echo off &setlocal
chcp 65001>nul
cd /d "C:\input"
for /f "delims=" %%a in ('dir /b /a-d *Â*.txt') do (
    set "fname=%%~a"
    setlocal enabledelayedexpansion
    set "nname=!fname:Â=!"
    ren "!fname!" "!nname!"
    endlocal
)
pause

Solution

  • An exclamation mark is always interpreted as beginning/end of delayed expanded variable reference if there is enabled delayed variable expansion. There must be a subroutine used to rename files containing one or more ! with removing them from the file name with disabled delayed variable expansion.

    @echo off & setlocal EnableExtensions DisableDelayedExpansion
    %SystemRoot%\System32\chcp.com 65001 1>nul
    cd /D "C:\input"
    (for /F "eol=| delims=" %%I in ('dir "*!*" /A-D /B 2^>nul') do set "FileName=%%I" & call :RenameFile) & pause & exit /B
    :RenameFile
    ren "%FileName%" "%FileName:!=%" & goto :EOF
    

    This batch file is designed for execution with a double click in Windows File Explorer or any other file manager resulting in the execution of %ComSpec% /C and the fully qualified file name appended as one more argument for the executed Windows Command Processor which is executed to process the batch file and then close itself.

    If the batch file should be used from within an opened command prompt window or should be called from another batch file, it would be better using following batch file:

    @echo off & setlocal EnableExtensions DisableDelayedExpansion
    for /F "tokens=*" %%G in ('%SystemRoot%\System32\chcp.com') do for %%H in (%%G) do set /A "CodePage=%%H" 2>nul
    %SystemRoot%\System32\chcp.com 65001 1>nul
    cd /D "C:\input"
    (for /F "eol=| delims=" %%I in ('dir "*!*" /A-D /B 2^>nul') do set "FileName=%%I" & call :RenameFile) & goto EndBatch
    :RenameFile
    ren "%FileName%" "%FileName:!=%" & goto :EOF
    :EndBatch
    %SystemRoot%\System32\chcp.com %CodePage% 1>nul
    endlocal
    

    This version restores the initial environment before exiting including the code page in addition to current working directory, command extension state and delayed variable expansion state as restored also by the first batch file because of an implicit execution of endlocal before cmd.exe is finally exiting the processing of the batch file.

    See the DosTips forum post [Info] Saving current codepage for an explanation of the second command line in second batch file.

    See single line with multiple commands using Windows batch file for an explanation of the unconditional command operator & used in both batch files multiple times for increasing the efficiency of batch file processing by reducing the number of times the batch file is opened, parsed and closed during its execution.