Search code examples
windowsbatch-fileutf-8robocopy

UTF8 support for robocopy in bat file


I am trying to make a bat file to sync a folder. I couldn't install WASL yet, so for now, rsync is not an option.

I wrote below code as neat as possible. Please check why it is not working? Note: On notepad++, On Encoding Menu, "UTF8" is chosen by default. And I tried to click "Convert to UTF8"; nothing happened.

Please Help!

CHCP 65001
REM @ECHO OFF

REM GLOBALS
SET V_PF=\\10.0.0.222\kalite_dokumanlar\
SET V_PT=C:\me\desk\KALİTE\

REM INIT
GOTO:F_MAIN

REM FUNCTIONS
:F_SYNC
    SETLOCAL ENABLEDELAYEDEXPANSION
        SET V_IN=%~1
        robocopy "%V_PF%%V_IN%\" "%V_PT%%V_IN%\" /MIR
    ENDLOCAL
EXIT /B 0

REM MAIN
:F_MAIN
call:F_SYNC "DESTEK"
call:F_SYNC "MÜŞTERİ ve TEDARİK"
call:F_SYNC "SİSTEM"
call:F_SYNC "ÜRETİM"

REM SAVE WITH NOTEPAD++ ENCODED UTF8 WITHOUT BOM

see the code at github


Solution

  • The directories synchronization task can be done with the following batch file:

    @ECHO OFF
    SETLOCAL EnableExtensions DisableDelayedExpansion
    @REM Get the current code page and remember it with the environment variable InitialCodePage.
    FOR /F "tokens=*" %%I IN ('%SystemRoot%\System32\chcp.com') DO FOR %%J IN (%%I) DO SET /A "InitialCodePage=%%J" 2>NUL
    @REM Change the code page to UTF-8.
    %SystemRoot%\System32\chcp.com 65001 >NUL
    
    @REM GLOBALS
    SET "V_PF=\\10.0.0.222\kalite_dokumanlar\"
    SET "V_PT=C:\me\desk\KALİTE\"
    
    @REM INIT
    GOTO:F_MAIN
    
    @REM FUNCTIONS
    :F_SYNC
        SET "V_IN=%~1"
        @REM /NDL /NFL: NO LOGS = NO GARBAGE CHARS CON:
        @REM /NJH /NJS: NO VERBOSE START-END 
        @REM /R:3: LIMIT RETRY 
        @REM /W:10: WAIT ON ERROR 
        %SystemRoot%\System32\robocopy.exe "%V_PF%%V_IN%" "%V_PT%%V_IN%" /MIR /R:3 /W:10
    EXIT /B 0
    
    @REM MAIN
    :F_MAIN
    CALL :F_SYNC "DESTEK"
    CALL :F_SYNC "MÜŞTERİ ve TEDARİK"
    CALL :F_SYNC "SİSTEM"
    CALL :F_SYNC "ÜRETİM"
    
    @REM Restore the initial code page.
    %SystemRoot%\System32\chcp.com %InitialCodePage% >NUL
    ENDLOCAL
    
    @REM SAVE THAT CODE ENCODED UTF-8 WITHOUT BOM
    

    The main correction is the removal of the backslashes at end of the source and destination paths on ROBOCOPY command line. %SystemRoot%\System32\robocopy.exe is different to most other Windows commands. It interprets \ left to " as an escape character for the double quote although no file/folder name can contain ever the character ". For that reason it is strongly recommended to avoid a backslash at end of the source and destination path. If that is not possible because of source or destination path is the root directory of a drive, then either the path is not enclosed in " at all or two backslashes are used at end of the path where the first backslash is escaping the second backslash to be interpreted as literal character. So working would be also:

    %SystemRoot%\System32\robocopy.exe "%V_PF%%V_IN%\\" "%V_PT%%V_IN%\\" /MIR /R:3 /W:10
    

    The usage of fully qualified file names for the executables reduces the number of file system accesses as the Windows command processor cmd.exe does not need to search for the executables in this case. The batch file becomes additionally independent on the environment variables PATH and PATHEXT with using fully qualified file names.

    The commands SETLOCAL ENABLEDELAYEDEXPANSION and ENDLOCAL inside the subroutine F_SYNC are of no use and for that reason removed from the code. There are instead inserted a SETLOCAL at top and an ENDLOCAL at bottom which define completely the local execution environment required for this batch file. For more details about these two commands see my answer on
    How to pass environment variables as parameters by reference to another batch file?

    There is also inserted a space between the command CALL (argument 0) and the label (argument 1) to avoid two files system accesses with return value invalid file name. call:F_SYNC is interpreted first as file name of an executable or script because of the missing space. This string is interpreted a second time by cmd.exe just because of the invalid file name error returns and split up next into the two arguments call and :F_SYNC with detecting now that call is an internal command of cmd.