How to optionally copy and rename a file in Windows?

37,375

Solution 1

This may be more than you need but with the proper tweaking it should do the job. I did some experimenting and it seems that if you use xcopy with the /D option and specify a destination filename, you will get a copy whether the files are the same or not. (Seems like it's basing the compare off the destination filename instead of the source.) So I only used xcopy to do the comparison but not actually to do the copy. (Thanks selbie for suggesting the /L option.) It seems rather large but if you remove the comments it's pretty small. This example copies and renames files that exist in the destination but are newer using the current date and time. It copies but does not rename files that don't exist in the destination (can be easily changed). And does not copy files that are the same. I can help you modify it to fit your specific needs.

@ECHO OFF
REM ### Note that this assumes all filenames end with ".txt".  This can be changed to suit your needs ###

REM ### Needed so the variables will expand properly within the FOR DO loops ###
Setlocal EnableDelayedExpansion

REM ### Set the source file(s) and call the "CopyIt" subroutine ###
SET Sourcefile=Test 1.txt
CALL :CopyIt

SET Sourcefile=Test2.txt
CALL :CopyIt

REM ### End of the program.  Otherwise the subroutine will run again ###
REM ### You can also just put an "EXIT" command here ###
GOTO END

REM ### The subroutine ###
:CopyIt
    REM ### Set the date and time to a variable called "DaTime" and remove offending ###
    REM ### characters (/ and :) that can't be used in a filename ###
    FOR /f "tokens=1-4 delims=/ " %%a in ("!date!") do SET DaTime=%%b-%%c-%%d
    FOR /f "tokens=1-3 delims=':'" %%e in ("!time!") do SET DaTime=!DaTime!_%%e-%%f-%%g

    REM ### Set a variable called "DestFile" to source filename minus ".txt" ###
    REM ### to be used to set the new destination file name + "DaTime" ###
    SET Destfile=!Sourcefile:.txt=!

    REM ### Check to see if the source filename exists in the destination directory ###
    DIR "C:\_Dest\!Sourcefile!" > NUL
    IF !ErrorLevel!==0 (
        REM ### If it does exist, set the loop count to 0 ###
        SET /a Count=0
        REM ### Have xcopy check to see if the source file is newer, but only report and not copy ###
        REM ### Thanks to selbie for suggesting the /L option ###
        FOR /f "tokens=1 delims=0" %%s in ('xcopy /Y /D /L "C:\_Source\!Sourcefile!" "C:\_Dest\"') DO (
            REM ### Increment the loop count ###
            SET /a Count=!Count!+1
            REM ### Only pick up the first iteration.  If the files are different, it will be the full path and the filename ###
            If !Count!==1 SET Source=%%s
        )
        REM ### If the source is the same as the destination, then !Source! will = " File(s)".  Change it to NONE ###
        SET Source=!Source: File^(s^)=NONE!
        REM ### If it's not equal to NONE, copy the file and rename it to source file + date & time + .txt ###
        IF !Source! NEQ NONE COPY /Y "!Source!" "C:\_Dest\!Destfile!-!DaTime!.txt"
    ) ELSE (
        REM ### If it does not exist, copy the file without renaming it ###
        COPY /Y "C:\_Source\!Sourcefile!" "C:\_Dest\"
    )
REM ### Exit the subroutine ###
EXIT /b

:END
pause

Solution 2

Create a file containing one line with the letter f in it (call it whatever you want, for this answer it will be f.txt).

Pipe the contents of f.txt to the xcopy command :

xcopy /Y /D c:\source\a.file c:\dest\b.file<f.txt

This will supply the answer to the (F = file, D = directory)? prompt that occurs if a file doesn't exist.

**Edit:**Just realized this basically duplicates the functionality of Rik's comment to the question, only his answer is more concise.

Share:
37,375

Related videos on Youtube

Paavo
Author by

Paavo

Updated on September 18, 2022

Comments

  • Paavo
    Paavo over 1 year

    Basically, in an automated batch file, I want to copy and rename a file if the destination file is missing or older. There are several variants, which do not quite work:

    copy /Y c:\source\a.file c:\dest\b.file 
    

    - always copies, no /D option or something

    xcopy /Y /D c:\source\a.file c:\dest\b.file
    

    - if destination does not exist, tries to ask if the destination is a file or directory, creating havoc in the automated build.

    robocopy /XO ... 
    

    - does not support renaming the file.

    It seems Windows has not managed to replicate Unix "cp -u" in 20+ years, or am I overlooking something?

    • Oliver Salzburg
      Oliver Salzburg over 10 years
      I don't think replicating Unix is any kind of priority for Windows.
    • Paavo
      Paavo over 10 years
      Yes, a better wording would have been 'replicating functionality of "cp -u"'.
    • Rik
      Rik over 10 years
      You could use echo f | xcopy /Y /D c:\source\a.file c:\dest\b.file ;) But do make sure it's an English Windows-version.
    • selbie
      selbie over 10 years
      Have you tried using the /I option with xcopy?
  • Paavo
    Paavo over 10 years
    No, this still displays interactive prompt if the destination does not exist.
  • Junior Mayhé
    Junior Mayhé over 9 years
    or echo f | xcopy a.txt b.txt /Y /D
  • Rik
    Rik almost 9 years
    I guess you missed the first line of the question where this needed to be done in an automated batch file without user interaction.
  • Richard A
    Richard A about 6 years
    A thorough solution. Do all the variables in the subroutine really need delayed expansion? They're not inside the FOR command and can be evaluated as normal % delimited variables, I think. Also, could be simplified using IF EXISTS rather than DIR then checking ERRORLEVEL, I think.
  • Richard A
    Richard A about 6 years
    /I only works if copying more than one file, in my experience.
  • Richard A
    Richard A about 6 years
    Also simplify by using GOTO :EOF rather than GOTO END and get rid of :END routine.
  • Richard A
    Richard A about 6 years
    Also, can use += when incrementing count.