Batch: Copy files where include and exclude conditions are met - batch-file

My requirement is to write a batch script that will compare the files in two folders. If a file exists in both SourceFolder and TargetFolder, then overwrite the file in TargetFolder with the file in SourceFolder.
Using a for-statement and an if-statement I can achieve this:
for /R %Source% %%G in (Prefix.*.ext) do (
if exist %Target%%%~nxG (
del %%G
copy %Target%%%~nxG %Source%
)
)
Although an additional requirement is to only copy files that start with 'prefix.' and end in '.ext' and also to exclude all files that contain the word 'exclude'.
In English: Copy all files from that source folder that start with 'Prefix.', end in '.ext', does not contain the text 'exclude'. and already exists in the target folder.
This is where I get stuck. Does anyone know how to do this in batch?

You can use xcopy for this. First, I am assuming that Prefix and ext are actual strings, to use variables instead you would have to wrap them like %Prefix%.
Second, you will have to make a new text file. Name it excludes.txt and put it in the same directory as your batch file. (If you don't want to make a batch file, then just put it in the directory that is active when you run the command). The only contents of this file should be your EXCLUDE string with no quotes, or other markup.
Ok, the command itself:
xcopy %Source%\Prefix.*.ext %Target% /U /EXCLUDE:excludes.txt
To break it down:
%Source%\Prefix.*.ext Selects the files in the source folder that start with Prefix and end with .ext
%Target% Specifies the destination for the files
/U Only copy files that already exist in the target directory
/EXCLUDE:excludes.txt This will read in excludes.txt and exclude any file that matches any part of the excludes.txt file.
That's it! This is probably easier than writing a FOR statement with a nested IF.

After reading this SO question, I ended up doing it like this. (Before the question got answered)
pushd %Target%
attrib +h *Exclude
for /R %%G in (Prefix.*.ext) do (
if exist %Target%%%~nxG (
del %%G
copy %Target%%%~nxG
)
)
attrib -h *Exclude
popd
The xcopy solution probably looks better although I'd prefer not to have to create (and remove) files if I can help it.

Related

Open multiple directories without knowing the names of said directories and delete folders within them using a Windows batch file

Okay, I do not really know how to describe fully what I want and I feel bad for asking something so advanced. I do not know how to do anything other than move folders and delete files and folders using batch.
I am trying to make a batch file to delete certain Steam files and folders which are used to cache data. I could easily make this for myself and call it a day however I would like to share it and have it work for other people also. The problem is one of the cache folders is named with a unique Steam identifier. I will put what I have made so far below.
REM Makes a temporary folder.
mkdir %LocalAppData%\Temp\steam_cache
REM Deleted all none essential files in Steam's configuration folder.
move "%ProgramFiles(x86)%\Steam\config\config.vdf" %LocalAppData%\Temp\steam_cache
move "%ProgramFiles(x86)%\Steam\config\loginusers.vdf" %LocalAppData%\Temp\steam_cache
rmdir "%ProgramFiles(x86)%\Steam\config" /s /q
mkdir "%ProgramFiles(x86)%\Steam\config"
move %LocalAppData%\Temp\steam_cache\config.vdf "%ProgramFiles(x86)%\Steam\config"
move %LocalAppData%\Temp\steam_cache\loginusers.vdf "%ProgramFiles(x86)%\Steam\config"
REM Delete all none essential files in Steam's userdata folder.
I will put what the file structure goes like below.
%ProgramFiles(x86)%\Steam\userdata\256283931
As you can see the number at the end is completely random and I do not know how to open that directory without knowing the number first. There are sometimes multiple of these folders with random names if you login with multiple account and I would like the batch file to go into them one by one and delete certain folder inside of them.
I will put below the folders that I would like to delete that are inside of the random numbered folder below.
%ProgramFiles(x86)%\Steam\userdata\256283931\ugcmsgcache
Sorry if what I am asking it too much if so just ignore this post, thanks.
What you are looking for is the for /D loop, which enumerates directories:
rem // Enumerate all directories under `userdata`:
for /D %%I in ("%ProgramFiles(x86)%\Steam\userdata\*") do (
rem // Check if there is really a sub-directory called `ugcmsgcache`:
if exist "%%~I\ugcmsgcache\" (
rem // Do something with the full path, like echoing, for instance:
echo "%%~I\ugcmsgcache"
)
)
If you want to ensure that the name of the enumerated directory/-ies name consist(s) of decimal figures only, you could use dir and findstr, together with a for /F loop:
rem // Change into parent directory, because `dir /B` returns plain directory names:
cd /D "%ProgramFiles(x86)%\Steam\userdata"
rem // Enumerate all directories under `userdata`, whose names are pure numbers:
for /F "delims=" %%I in ('
dir /B /A:D "*" ^| findstr /I /X "[0123456789]*"
') do (
rem // Do something with the full path, like echoing, for instance:
echo "%%~fI\ugcmsgcache"
)
The cd command could also be replaced by pushd and popd.
The ~f modifier ensures that the full path is derived, related to the current working directory.
Note that the pipe (|) needs to be escaped here, because it is in the set of the for /F loop.

Replace file.old with file.new in multiple subfolders

I am trying to replace over 400 audio files, in just about as many sub-folders, with a updated format required by the program. It's the same file in each location but its how they require it for their xml file. I found several similar post, replacing files in multiple sub-directories like this one Replacing a file into multiple folders/subdirectories this I assumed would meet my needs.
I want to find all AR33.mp3 files in SFX'x folders, and replace with the new required AR33.wem my issue is as follows:
FOR /R C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\GoldenEye\SFX %%I IN (AR33.mp3) DO echo COPY /Y C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\sfxwems\AR33.wem %%~fI
This does the reverse and copies the file I want to overwrite, ar33.mp3, all over the folder structure in every folder where there shouldn't be any. but it does say 1 file copied after each entry.
(AR33) creates extension-less copies. adding (*AR33.mp3) does nothing, same with (*AR33.mp3 *) does nothing, even with "1 item copied" pointed out in the console. At this point I'm trying what I can to get this to work randomly doing stuff. Changing COPY to replace give a invalid switch -/y. Am I using the wrong "script" to do what I want? Because even changing one of the AR33.mp3 over to a .wem didn't see any change after replacing the line .mp3 to .wem. I assume I need to fix what its searching for and what its copying.
Updated bat:
FOR /R "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\GoldenEye\SFX\" %%I IN (AR33.mp3) DO echo COPY /Y "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\sfxwems\AR33.wem" "%%~fI"
Output sample:
C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted>echo COPY /Y "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\sfxwems\AR33.wem" "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\GoldenEye\SFX\AAC0\ShipName__PASC045\isPlayer__False\AR33.mp3"
COPY /Y "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\sfxwems\AR33.wem" "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\GoldenEye\SFX\AAC0\ShipName__PASC045\isPlayer__False\AR33.mp3"
You want to replace .mp3 with .wem as well. For now you are simply copying the .wem file and naming it with a .mp3 extension. So we could just rename the .mp3, then copy the .wem file to it.:
#echo off
for /R "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\GoldenEye\SFX\" %%I in (*AR33.mp3) do (
echo ren "%%~fI" "%%~nI.wem"
echo copy /Y "C:\Users\trevo\Desktop\ProjectGoldenEYE\811converted\sfxwems\AR33.wem" "%%~dpnI.wem"
)
Please take note before continuing. The above will only echho the result, once you are happy that it does what you want, then only remove `echo from both strings in the code block.
It is also always a good idea to backup files before running a big copy process like this.

How to loop in a folder with batch file

I need to do something with a batch file....
I need to copy a folder to another folder but...
If the new folder exist, I need to verify if the file in new folder exist, then I need to rename the file with «.old» at the end of this file before to copy the new file.
I have a great experience of programming in Java, php etc, but not really with batch file...
I m using a syntax of java/php to explain my problem....
set folderOrigin=d:\test1
set folderFinal=d:\test5
if EXIST %folderFinal% (
for (fileOrigin : folderOrigin){
variableNamefileOrigin = fileOrigin
for (fileFinal : folderFinal){
variableNamefileFinal = fileFinal
if (variableNamefileOrigin == variableNamefileFinal){
newvariable = variableNamefileFinal + ".old"
ren variableNamefileFinal newvariable
xcopy /s /q %folderOrigin%+%variableNamefileOrigin%
%folderFinal%+%variableNamefileFinal%
}
}
}
) else (
xcopy /s /q %dossierOrigine% %dossierDestinataire%
)
pause
Thx everyone !
Assuming that the source directory ("folders" are artifacts in the GUI; the structures in the filesystem are "directories") is %sourceFolder% and the destination directory is %finalFolder%; and also assuming that you need to copy only files (not an entire subtree):
To loop through the files in %sourceFolder% you use a for loop:
for %%f in ("%sourceFolder%\*") do call :copyOneFile "%%~f"
exit /b
In the subroutine :copyOneFile you have the current file as %1. To check whether it exists in %finalFolder% you use if exist, and if so you rename it, but not before checking if the .old file exists already:
:copyOneFile
if exist "%finalFolder%\%~nx1" (
if exist "%finalFolder\%~n1.old" del "%finalFolder\%~n1.old"
ren "%finalFolder\%~nx1" "%~n1.old"
)
Now you can copy the file from the source folder to the destination folder:
copy "%~1" "%finalFolder%
To understand the constructions %~nx1 and so on, use for /?. Note than the second argument of ren must have only the filename, a path is not allowed.
If you need to copy an entire subtree then:
After copying the files, redo with for /d to get directories.
Use the appropriate commands instead of del and copy.

How to rename a file while it is being copied and copy complete

I want to create a script which should copy files from one folder to another.
Since a file can be of a large size, of up to 1000 MB, it may take few seconds
or a minute to completely copy it. While this is being happened, I want the filename in a destination folder to be prefixed with an underscore(_).
Once the file is completely copied over to a destination folder, then the _ should be removed from the filename. The purpose of doing this is to make sure that another process should not pick up the incomplete file from the destination folder.
How can we do this using a batch script? Currently my batch file is copying and moving the file to another folder but I don't know how can i prefix underscore and then remove again from the filename after the file is completely moved.
Here is my 2 line code which is copying and moving the file.
copy %1\Customer_*.xml C:\Users\ard\Documents\Folder1
move %1\Customer_*.xml %1\Archive
If this can't be done using batch script, then VB script should also work
What you want, in words:
For each affected file in C:\source:
Copy file x to C:\destination\_x
Rename file C:\destination\_x to C:\destination\x
and in Windows batch code, with a few extras:
#echo off
setlocal
set "SOURCE=%1"
set "DESTINATION=C:\Users\ard\Documents\Folder1"
for /f "usebackq delims=" %%x in (`dir /b "%SOURCE%\Customer_*.xml"`) do (
if exist "%DESTINATION%\%%x" (
echo %%x - already exists at destination
) else (
echo %%x
copy "%SOURCE%\%%x" "%DESTINATION%\_%%x" > NUL && rename "%DESTINATION%\_%%x" "%%x"
)
)
Notes:
the for loop can iterate a command's output line-wise
in our case, that command is dir /b "%SOURCE%\*.xml", i.e. the "bare" list of matching files in the source folder
usebackq means the command is delimited by backticks, which allows using double quotes inside the command itself
delims= sets the field delimiters to "none", otherwise for would split each filename into tokens if it contained spaces
> NUL suppresses the "1 file(s) copied." success messages from copy
&& means that rename is only executed if copy was successful
Removing a prefix is not trivial, but removing a suffix (new extension) is simple. So I would append a new extension like .inProgress. You can then COPY and RENAME a collection of files with two simple commands using wildcards.
But the MOVE command does not allow renaming multiple files, so a FOR loop would be required. I'll show the code, but I don't think it is really necessary in the OP's scenario. It looks to me like the source and destination folders are on the same drive, so the move should be virtually instantaneous, and there should be no need to use a temporary intermediate name.
copy "%1\Customer_*.xml" "C:\Users\ard\Documents\Folder1\*.*.inProgress"
ren "C:\Users\ard\Documents\Folder1\*.inProgress" *.
for %%F in ("%1\Customer_*.xml") do (
move "%%F" "%1\Archive\%%~nxF.inProgress"
ren "%1\Archive\%%~nxF.inProgress" *.
)
See How does the Windows RENAME command interpret wildcards? for information on why the rename works.
Note that all the copied files will show up as ".inProgress" until the entire COPY operation has completed. If you want each file to be available as soon as possible, then a FOR loop is needed for the COPY as well:
for %%F in ("%1\Customer_*.xml") do (
copy "%%F" "C:\Users\ard\Documents\Folder1\%%~nxF.inProgress"
ren "C:\Users\ard\Documents\Folder1\%%~nxF.inProgress" *.
)
My example copies from src to dest with a new name, then restores back the old name:
bn is the basename of the source file.
for %%a in (src\*.xml) do (
set bn=%%~nxa
copy %%a dest\!bn!_
rename dest\!bn!_ !bn!
)

How to get first file in subfolder while recursing through subfolders using windows batch

I am currently trying to make creating par2 recovery files a little easier for myself. The following script goes through all the current-folder's subfolders and then creates par2 recovery files for all files in said subfolder.
FOR /R %%g IN (.) DO C:\WINDOWS\par2.exe c -r10 -s384000 "%%g\%%~ng.par2" "%%g\*"
del /q *.par2
pause
But now I have one issue, it uses the folder name as a filename for the par2 files but strips the "extension" like it would for a file. The folder names are something like "ConcertFootage1.avi_". That folder will then contain files like ConcertFootage1.avi.part01.rar and ConcertFootage1.avi.part02.rar and so on. Meaning I end up with par2 files like "ConcertFootage1.par2" where it should be "ConcertFootage1.avi.par2" in order to match the files in the folder correctly.
Now, even if it would not strip the "extension" from the foldername I'd still end up with "ConcertFootage1.avi_.par2" so I figured it would be best to just get the name of a file in the folder and use that as a base, meaning it would just strip the ".partX.rar" file-extension and that is exactly what I need.
I can't figure out how to do this in the "FOR DO" command though, can anyone help?
I understand your question, that you try to strip two extensions from a filename.
You can do it with two %~nX flags.
setlocal EnableDelayedExpansion
for /R %%g IN (.) DO (
set "filename=%%~g"
call :removeExtension result1 "!filename!"
call :removeExtension result2 "!result1!"
echo !filename! -- !result1! -- !result2!
)
exit /b
:removeExtension
set "%~1=%~n2"
exit /b

Resources