Automate file replacement - batch-file

I have a task to rename a file and place another file with same name in the same folder
Like for e.g. a folder C:/test I have multiple files .txt (suppose test.txt is the one needed rename and replace)
I want to rename test.txt to test_bkp%date% and place new file there.
Need help to start the logic.
#ECHO OFF
SET "sourcedir=C:\Users\test\new"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%C:\Users\Test\new\%filenames%.txt" '
) DO (
SET "filename=%%a"
ECHO REN "%C:\Users\Test\new\%%a C:\Users\Test\new\%%a_bk_date.*%"
)
GOTO :EOF
Let me explain what I am trying to achieve. I get file with updated data often. I cannot just go ahead and replace the old file with new. I have to take a backup and place the new file in the folder.
This is my first try using batch scripting

As soon as you write a new version of a file into the same folder than the original (with the same name), it's already too late to rename the original - it doesn't exist anymore. You need two folders: one that receives new versions (new) and one where you keep your renamed files plus the new ones (old)
#ECHO OFF
setlocal
set "source=C:\Users\test\new"
set "destin=C:\Users\test\old"
set "files=*.txt"
REM for every matching file in the source folder:
for %%A in ("%source%\%files%") do (
REM if there is such a file in the destination folder, rename it:
if exist "%destin%\%%~nxA" ren "%destin%\%%~nxA" "%%~nA-%date%%%~xA"
REM only then copy the file:
copy "%%~fA" "%destin%\"
)
This will fail if you run it more than once per day. (More code needed to handle that; for example, adding time too)
It will also fail if your %date% contains characters that are not allowed in file names (my %date% looks like 29.01.2019). (More code needed to handle that; for example %date:/=-%)

Related

Batch file to rename files with complex names and back again

Reviving an old topic once discussed here, as I have a similar problem. The solution proposed in the old thread worked only in half in my case.
I need first to rename various media files (mp4, mp3, wav...) with irregular, sometimes complex names as 1.mp3, 2.mp4, 3.wav, etc. And some time after I need to restore the original filenames. File extensions should remain the same in both cases.
In a more specific case of renaming .raw files Helbreder proposed two .bat scripts. The first .bat changes filenames to 1.raw, 2.raw, 3.raw, etc. and creates corresponding individual .txt files each of which keeps the original filename. The second .bat takes the original filenames from individual .txt files and renames 1.raw, 2.raw, 3.raw, etc., back to the original.
For my purpose I slightly modified the first .bat proposed, and this works perfectly well:
#echo OFF
#setlocal ENABLEDELAYEDEXPANSION
set I=1
for %%G in (*.mp3 or *.3gp or *.wav or .mp4) do (
set ORIGINAL_NAME=%%~nG
set ORIGINAL_EXTENSION=%%~xG
(
REM Try to rename file
ren "%%G" "!I!"!ORIGINAL_EXTENSION!
) && (
REM Renaming was successful
> "!I!.txt" echo !ORIGINAL_NAME!!ORIGINAL_EXTENSION!
set /A I+=1
) || (
REM Renaming was a failure
echo Cannot rename [!ORIGINAL_NAME!] file.
)
)
#endlocal
Put in a destination directory, this .bat renames all media files, keeping the correct extensions, and generates a set of .txt files each of which contains the original filename with extension.
For instance, 1.txt contains a string "Play 2019-03-06 in C.mp3" which was the original filename.
Then I need to reverse the original filenames and I run the second unmodified Helbreder's .bat. For commodity purpose I paste it here:
#echo OFF
#setlocal ENABLEDELAYEDEXPANSION
for %%F in (*.txt) do (
set BASENAME=%%~nF
REM Read original name from txt file
for /F %%G in (%%F) do (
REM iterate over all corresponding files
for %%H in (!BASENAME!.*) do (
set EXTENSION=%%~xH
REM Remove dot from extension string
set EXTENSION=!EXTENSION:~1!
if not "!EXTENSION!" == "txt" (
REM Process files
(
REM try to rename corresponding file to old name
ren "!BASENAME!.!EXTENSION!" "%%G.!EXTENSION!"
) && (
REM Operation was successful - remove TXT file
del /F /Q "%%F"
) || (
REM Something went wrong
echo Cannot restore old name for file [!BASENAME!.!EXTENSION!].
)
)
)
)
)
#endlocal
As my filenames may be complex and often include blank spaces, this second .bat works in a half-successful way.
It reverted the first original filename "Play 2019-03-06 in C.mp3" written to a 1.txt with extension, as simply "Play.mp3". It also ignored a part of the second complex filename which followed blank space, keeping only "2007-03-06.mp3" instead of "2007-03-06 output.mp3". And it successfully reverted only those filenames which were composed of numbers and underscores, without blank spaces.
As far as I understand, the issue consists in the way the second .bat retrieves the filename from the text string kept in .txt file. The first blank space occurring in the text line is considered as the end of a filename.
Could you kindly suggest a solution for reverse renaming of any files from the correspondent .txt record, which may contain letters, numbers and blank spaces (and maybe special characters, like "&" and some others).
Following Compo's advise I tried another code from the old post, this time proposed by Jeb.
After a slight modification to make it match to different file types and - important! - to keep their original extensions, the code seems to work, but with issues.
When there is more than one dot in the filename the name revert code does not restore it completely, even though it is correctly saved in the .txt file by the rename batch. For example the second batch truncates "Play 2020.10.12.mp4" to "Play 2020" and does not wish to restore the extension.
Placed in directories with many files the rename batch sometimes does not rename a part of the list, sometimes does not do the job at all and sometimes renames all files flawlessly. I first thought the partial script dysfunction might be related to the presence of special signs in the filenames, like commas or parenthesis. But no, when I delete special signs, this changes nothing. Just puzzled.
So, the new version of code is only partially solving the problem. Is there something to correct in the code, to make it more universally working? Which solution could be applied in these two cases?
I divided the code into two separate .bat files to rename and to revert original filenames.
The both follow.
Rename:
#echo off
set cnt=0
del Names.txt > nul 2>&1
echo Running Batch Rename
for %%f in (*.mp3 or *.mp4 or *.3gp or *.wav) do (
set "file=%%f"
set "EXTENSION=%%~xf"
CALL :renameToNumber
)
:renameToNumber
set /A cnt+=1
set "number=00000%cnt%"
set "number=%number:~-4%"
(echo %number% %file%) >> Names.txt
ren "%file%" %number%"%EXTENSION%"
exit /b
Revert the original names:
for /F "tokens=1,*" %%A in (names.txt) DO (
set "number=%%A"
set "filename=%%~nB"
call ren %%number%%.* "%%filename%%.*"
call echo ren %%number%%.* "%%filename%%.*"
)
exit /b

How can I improve a batch file with a conditional who copy a jpg file refferring to a specific extension and to a specific database?

I created a .bat file with the following code in order to copy a random file from a directory A-POOL FOLDER into a directory B-FOLDER (with a fixed file name video.mp4). So, in the directory A there is a pool of .mp4 file, and in the directory B there is the the file video.mp4 (same name, but different video every time I execute my batch-file).
That's a code who do this. It perfectly works.
#echo off
setlocal EnableDelayedExpansion
cd C:\Users\aless\Desktop\example\A-POOL
set n=0
for %%f in (*.*) do (
set /A n+=1
set "file[!n!]=%%f"
)
for /L %%i in (1,1,%time:~-1%) do set "dummy=!random!"
set /A "rand=(n*%random%)/32768+1"
copy "!file[%rand%]!" C:\Users\aless\Desktop\example\B-FOLDER\video.mp4
FOR %%G IN ("!file[%rand%]!") DO >"C:\Users\aless\Desktop\example\B-FOLDER\title.txt" ECHO %%~nG
Now the question (different from last time):
In the directory A-POOL I have a lot of .mp4 files. I changed manually the .mp4 extension of every file with a code who rappresent a food.
For example: Filename.pizza, Filename2.pizza, Filename.pasta, Filename200.pasta, Filename.cheeseburger etc...
I created another folder named "FOOD-DATABASE" (in C:\Users\aless\Desktop\FOOD-DATABASE) who contains a big database of images in .jpg extension of the foods. The file NAMES of the food database are equal to the file EXTENSIONS of the files contained in A-POOL folder
Content of FOOD DATABASE folder:
(pasta.jpg, pizza,jpg, cheeseburger.jpg... etc..).
So I need to add to the code a string/conditional who execute e command who say:
If the picked random File have the extension .pizza COPY pizza.jpg from C:\Users\aless\Desktop\FOOD-DATABASE into C:\Users\aless\Desktop\B-FOLDER\FOOD.JPG (fixed name file)
Actually I don't want to add this strings for every food type... in few word the code strings have to read the extension of the picked random file and copy from C:\Users\aless\Desktop\FOOD-DATABASE to C:\Users\aless\Desktop...B FOLDER\FOOD.JPG (fixed name file) the file with the same name to the extension of the random file.
It's a mess... I know ;) Thanks for your help!
As mentioned in the comments, we know that the extension of the one file is the name of another file. so these variable expansions are important:
%%~nG
%%~xG
The last for loop sets a variable %food% from expanded %%~xG which is the extension of the file and using a random example would be .pizza We just need to get rid of the . and you have pizza. We do this by %food:~1.
#echo off
setlocal EnableDelayedExpansion
pushd "%userprofile%\Desktop\example\A-POOL"
set n=0
for %%f in (*.*) do (
set /A n+=1
set "file[!n!]=%%f"
)
for /L %%i in (1,1,%time:~-1%) do set "dummy=!random!"
set /A "rand=(n*%random%)/32768+1"
copy "!file[%rand%]!" "..\B-FOLDER\video.mp4" /Y
for %%G IN ("!file[%rand%]!") DO (
echo %%~nG > "..\B-FOLDER\title.txt"
set "food=%%~xG"
)
copy "..\FOOD-DATABASE\%food:~1%.jpg" "..\B-FOLDER\food.jpg" /Y
popd
Notes!
I am using pushd instead of cd and using relative path, not full paths as we are working in the same folder structure.
I can make out that you are running this on your own profile, so I replaced C:\users\<username> with %userprofile% in the event someone else wants to run it from a similar folder, their <username> will be different.
popd at the bottom of the script simply changes back to the previous working directory you were in before the last pushd. it is not needed for this particular script, but adding it so you can learn about it compared to pushd
All of the items I modified has some good help topics, you can find help topics on cmd by simply running the command name with an appended /? for instance for /?, set /? etc.

Windows command line renaming files in subfolders?

I didn't find so far a similar question, so I try to explain the problem:
I have large number of files that are in subfolders inside "C:\images"
I have a list of names in two columns, so that 1st column is old filename and 2nd is a new filename. I want to change that list into a batch file.
Names are pretty unique so I want to make batch file - so that will be one command for every file to be renamed.
RENAME "C:\images\768e11ab.jpg" "4ca5d042.jpg"
RENAME "C:\images\5402c708.jpg" "b802820b.jpg"
RENAME "C:\images\1c039e0e.jpg" "80ce9797.jpg"
etc...
It is rather simple, only, files are scattered across subfolders. Is there any way to make a command so it will look for that specific file in all subfolders in "C:\images" and rename it.
Following some similar questions tried this, with no result:
for /r "C:\images\" "%%~G" (768e11ab.jpg) do "4ca5d042.jpg"
Also, tried to use some renaming application for this but they freeze when I try to rename big list of files, so I would avoid them and use batch file. Also, I would like to use this way where there is one line in batch file for every file because it is simpler for me to use it (and change it later). I appreciate your help.
Approach the problem from the other side. Instead of looping over the image files, loop over the text file.
Assuming your textfile to be something like
"768e11ab.jpg" "4ca5d042.jpg"
"5402c708.jpg" "b802820b.jpg"
"1c039e0e.jpg" "80ce9797.jpg"
Then the code could look like:
#echo off
REM read each line; %%A is the first column, %%B is the second one
for /f "tokens=1,2" %%A in (list.txt) do (
REM search the image file %%A
for /R "C:\Images\" %%C in ("%%~A") do (
REM %%C now holds the full path of %%A
ECHO ren "%%~C" "%%B~%%~xC"
)
)
If your list looks different, the tokens and perhaps the delims for the for /f loop have to be adapted.
NOTE: the ren command is just echoed for security reasons. Once you verified it does exactly what you want, remove the ECHO to enable the * ren` command.

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!
)

Loop to search files efficiently starting from last modified file

I have a folder containing around 50 subfolders (called 0001, 0002, 0003... etc) and each contain hundreds of files (called 0001_132.txt, 0002_312.txt, 0032_152.txt... etc), and I need to run a batch file to extract files that I haven't processed since the last run of the batch file.
The way I currently do it is saving a .txt file telling me the filename of the last file being extracted during the last update. Next time I run the batch file, it loops through subfolders until reaching that particular filename and then start extracting the files newer than that particular file.
I am not sure if the way I do it is good or not but it works. HOWEVER, since I have many files in the folder, each time the batch file reads all old files before extracting new ones, which causes the program to run for quite some time. So, I would like to ask, if there is any way to not loop through those old files?
The file recording the last updated files looks something like this:
last_update.txt: format([subfoldername]_[file].txt)
eg: 0001_134
0002_213
.
.
0050_241
and my batch looks something like this:
for /f %%a in (C:\last_update.txt) do (
set number=%%a
set "subfolder=!number%:~0,4!"
set reach=0
for /f %%x in (c:\data\subfolder\) do (
if %%~nx==!number! (
set reach=1
)
if not %%~nx==!number! if !reach!==1 (
DO THE EXTRACTION
)
set latest_File=%%~nx
)
echo !latest!>>last_update_temp.txt
)
del last_update.txt
ren last_update_temp.txt last_update.txt
If you use the attrib command to clear the archive bit after processing your files, then you can use xcopy with /l to get a list of the new files with the archive bit set.
Here is an example - assuming the files have already been processed and new files are waiting with the archive bit set. The last line removes all the archive attributes once the files have been processed.
All it does is in the loop below is echo the drive:\folder\filename.txt of each file with the archive attribute set, and pause.
It uses a temporary file because of the number of files being processed, which could otherwise cause a long delay.
#echo off
dir *.txt /aa-d /b /s >file.tmp
for /f "delims=" %%a in (file.tmp) do (
rem do your task with all the files
echo "%%a"
pause
)
del file.tmp
attrib -a *.txt /s

Resources