copy and rename file with create date (Batch script) - batch-file

I have some of log files formatted like this "name.log"
I would like to copy those from one folder to another folder like
xcopy /y "C:\Folder1" "D:\Folder2"
Adding I need to rename file with created date of original file (no copy file) so that the text file in Folder2 would be like "yyyymmddhhmm.log" if some file has the same name (date of creation) it will be overwritten.
I have a code with help of #Wes Larson but there is something wrong.
set Source=C:\Users\user1\Desktop\1
set Dest=C:\Users\user1\Desktop\2
if not exist %Dest% md %Dest%
for /F %%a in ('dir /b "%Source%\*.txt"') do call :Sub %%a
goto :eof
:Sub
set "filename=%1"
for /F %%s in ("%Source%\%1") do if %%~zs==0 goto :eof
set "datepart="
FOR /F "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%filename%" ^| findstr "%filename%"') DO (
IF "%%c" neq "" SET "datepart=%%c%%a%%b%%d%%e"
)
FOR /F %%a IN ("%filename%") DO (
set "NewName=%%~na %datepart%%%~xa"
)
xcopy /y "%Source%\%filename%" "%Dest%\%NewName%*"
GOTO :EOF
The problem is that If I don't put the .bat in the same folder that origin files (Folder1),some files aren't change name. For example, if it is out some files change name with old name and one white space. The command windows tell me that it doesn't find the file when it get the creation date. It's very strange because some files are copied well.
What do I need to solve this problem?

Before we get to an answer: When troubleshooting/debugging batch scripts, don't use #echo off. It's great once you have it working the way you want, but comment it out when you need to see what your code is doing line by line. Also, you'll want to open a cmd window and run your script from a command line, so the window doesn't close as soon as your script finishes.
Now on to your code. This for loop is part of your problem:
FOR /f "tokens=1-3delims=/-:" %%a IN ('dir /tc "%filename%"') DO IF "%%c" neq "" SET "datepart=%%a-%%b-%%c"
Firstly, you haven't set %filename%, so this loop will fail. You should probably have a line in your :Sub like this:
set "filename=%1"
Now, assuming that %filename% is fixed, by the time this loop has finished, your %%a, %%b, and %%c variables have been set to the values in the last line of output from the command 'dir /tc "%filename%"', which is something like X Dir(s) XXX,XXX,XXX,XXX bytes free, and isn't the information you're looking for.
So, instead, you can tweak it a little so that you pipe the output of dir to findstr, looking for just the one, single line that you want to use, like this:
FOR /f "tokens=1-3delims=/-:" %%a IN ('dir /tc "%filename%" ^| findstr "%filename%"') DO (
IF "%%c" neq "" SET "datepart=%%a-%%b-%%c"
)
But then, you have another problem: your %datepart% looks like MM-DD-YYYY hh. This is because you changed your delims from the default (which includes spaces and tabs), to only the specified characters. Also, from your question, you want to also include hour and minute all formatted as "yyyymmddhhmm.log" , which means you'll need those next two tokens, too. Then your line becomes this:
FOR /f "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%filename%" ^| findstr "%filename%"') DO (
IF "%%c" neq "" SET "datepart=%%c%%a%%b%%d%%e"
)
Next, your nested for loop is confusing, unnecessary, and causing problems:
FOR /f %%a IN ("%filename%") DO FOR /f %%d IN ("%datepart%") DO (
set NewName="%%~na %%d%%~xa
xcopy e/d/y "%Source%\%OrgName%" "%Dest%\%NewName%"
)
You already have the %datepart% variable, and you don't need to turn it into one of the for %%d variables to be able to reference it. So it becomes much simpler when you do it like this:
FOR /f %%a IN ("%filename%") DO (set "NewName=%%~na %datepart%%%~xa")
Also, because you run into delayed expansion issues, it's simpler to take the xcopy command out of the loop.
And once again, you have a variable %OrgName% that you never set. Fortunately, this is actually unnecessary as you already have the original file name captured as %filename%. So your overly complicated nested for loop becomes this:
FOR /f %%a IN ("%filename%") DO (
set "NewName=%%~na %datepart%%%~xa"
)
echo xcopy e/d/y "%Source%\%filename%" "%Dest%\%NewName%"

Related

Batch file to append several text documents to one document

I have created a batch file which should do several things, including appending all text documents of a certain format into one text file provided there are more than one text files of this format in the directory. This section of the code is below:
:multiple
SET /a count=0
ECHO.> "%location%\UAV_camera_coords_all.txt"
FOR /r "%location%\Output" %%G in ("UAV_camera_coords_*.txt") do set /a count+=1
IF %count% GTR 1 (
FOR /r "%location%\Output" %%G in ("*.txt") DO (
SET file=%%~G
TYPE "%file%">>"%location%\UAV_camera_coords_all"
)
GOTO :end
It seems that the code is crashing upon reaching the if statement even though the count variable is greater than one. None of the code in the if statement is executed and indeed none of the code which should come after the if statement is executed either. Is there any syntax or other error which may be causing this?
Besides my comment. I assume that you are not really planning on typing the output of *.txt but instead only UAV_camera_coords_*.txt.. if not, feel free to change it back to *.txt
#echo off
for /f "tokens=1,*" %%i in ('dir /s "%location%\UAV_camera_coords_*.txt" ^| findstr "File(s)"') do set cnt=%%i
if %cnt% gtr 1 (
for /f %%a in ('dir /b /s "%location%\UAV_camera_coords_*.txt"') do type "%%~a"
)>"%location%\UAV_camera_coords-all.txt"
Note, I changed the output filename to be -all and not _all as that would type the file onto itself if it was to be a txt file as well.
Edit adding back original answer, before I realised you were recursively searching through directories:
#echo off
for /f "tokens=1,*" %%i in ('dir "UAV_camera_coords_*.txt" ^| findstr "File(s)"') do if %%i gtr 1 type "UAV_camera_coords_*.txt">>"%location%\UAV_camera_coords_all"
Just for the purpose of providing an alternative, this one uses xcopy to check the file count, and copy to merge them.
PushD "%location%\Output" 2>NUL && For /F %%G In ('""%__AppDir__%xcopy.exe" "UAV_camera_coords_*.txt" . /SQL"')Do If %%G Gtr 1 Copy /Y /B "UAV_camera_coords_*.txt" "..\UAV_camera_coords_all.txt">NUL & PopD

Batch File to move files to folders base on part of their name

I am looking for one solution, which will help me to move files to folders with similar name.
I have filenames like TEST1_2018P2.xlsx, TEST2_2018P2.xslx, etc.
And I have folders with names TEST1_City1, TEST2 City2...
What I need is to move file TEST1_2018P2.xlsx to folder TEST1_City1, TEST2_2018P2.xslx to TEST2 City2 and so on.
How can I do that?
Here's my latest code, which is also not working.
#ECHO OFF
SETLOCAL
SET "sourcedir=my_folder"
SET "destdir=my_folder"
FOR /f "delims=" %%a IN ( 'dir /b /a-d "%sourcedir%\*.xlsx" ' ) DO (
FOR /f "tokens=1delims=" %%b IN ("%%a") DO (
FOR /f "delims=" %%d IN ( 'dir /b /ad "%destdir%\*%%b*" ' ) DO (
ECHO(MOVE "%%a" "%destdir%\%%d\"
)
)
)
GOTO :EOF
I'm not sure of your exact task, so this relatively basic example should move any .xlsx file to the first existing directory whose name matches the portion of the filename up to the underscore, plus a space.
Adjust the values on lines 2 and 3 to match your actual directory specs, (without trailing backslashes).
#Echo Off
Set "SourceDir=my_folder"
Set "DestDir=my_folder"
For /F Delims^=^ EOL^= %%A In ('Dir /B/A-D-L "%SourceDir%\*_*.xlsx" 2^>Nul'
) Do Call :Sub "%%A"
GoTo :EOF
:Sub
Set "DirName=%~1"
Set "DirName=%DirName:_="&:"%"
For /F Delims^=^ EOL^= %%A In ('Dir /B/AD-L "%DestDir%\%DirName% *" 2^>Nul'
) Do If Exist "%SourceDir%%~1" Move /Y "%SourceDir%\%~1" "%DestDir%\%%A" 2>Nul
Exit /B
It was not designed to be the most efficient method of performing the task!
Please also note that your existing directory names did not have a clear pattern so this was written for TEST1 City1 TEST2 City2 etc.
If they are all underscores, e.g. TEST1_City1 TEST2_City2 etc. then change "%DestDir%\%DirName% *" on line 11 to "%DestDir%\%DirName%_*".
If the directories can be either of them, and you are sure that no two directories will begin with the string TEST1, TEST2 etc., (which would limit you to only numbers 0..9 in this case), you could probably use "%DestDir%\%DirName%?*" on line 11 as an alternative.
Assuming that actual text of TEST1 doesn't contain any _ characters, you can use:
#echo off
setlocal EnableDelayedExpansion
cd /d "your_folder"
for /F "delims= eol=" %%A IN ('dir /B /A-D "TEST*_2018P2.xlsx"') do (
for /F "tokens=1 delims=_" %%B IN ("%%A") do (
rem Define some important variables:
set "token_1=%%B"
set "num_test=!token_1:~-1!"
set "foldername=!token_1!_City!num_test!"
md "!foldername!\" >nul 2>&1
move "%%~fA" "!foldername!\"
)
)
Let me explain my code:
The first for /F loop is used to find all the files you want (TEST*_2018P2.xlsx) excluding all directories (/A-D) and headers. delims= and eol= options are used: loop through the whole line without skipping lines starting with ;.
The second for /F loop is used to get the first token of the output of the first loop (IN ("%%A")).
The first token is set to token_1 variable and then substract the last number/letter from it setting it to the num_test variable.
A foldername is set because it is used two time, it is really hard to understand this code without setting it in a variable. It is actually set by token_1 variable (TESTn), _City and n (number).
A folder is created with that name. Both STDIN and STDERR are redirected to nul. This happens not to have many processed if exist statement. The current file (%%~fA; full path) is moved to this folder.
Remember to replace "your_folder" with your actual folder!

Batch - Returning full path from a dir /b

I am traversing folders on a drive, collecting file names with specific extensions, and building a string which is later used in a command line switch. When I find a qualifying file I need to know its full path as this is what is required by the command line. I currently use "%~dp0%%a\%%b" to build the full path, but I can see that may have limitations later on when the batch becomes more complex (e.g. it digs deeper into sub folders). I am hoping there is a way to replace "%~dp0%%a\%%b" with the path to the located file. Thank you:
#ECHO OFF
for /f "usebackq tokens=*" %%a in (`dir /b /a:d`) do (
pushd %%a
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%b in ('dir /b "*.E01" "*.L01" "*.AD1" 2^>nul') do (
SET EVIDENCE_STR=!EVIDENCE_STR! /e:"%~dp0%%a\%%b"
)
IF DEFINED EVIDENCE_STR (
ECHO !EVIDENCE_STR!
) ELSE (
ECHO No evidence files located in: %%a
)
endlocal
SET EVIDENCE_STR=
popd
)
PAUSE
Why do you need to create 2 loops, each running a dir command to find files? Why not just do for /R loop? Here is an example:
#echo off
set "files=*.E01 *.L01 *.AD"
for /R %%a in (%files%) do echo %%a
Simply use "Sub"-Option: /S of the DIR-Command:
Dir /B /S C:\*.jpg
cause it is that equivalent to:
#echo off
set "DirPath=C:\"
set "files=*.jpg"
for /R %DirPath% %%a in (%files%) do echo %%a
and so you should got the same result in each script.
The Problem: If you don't want any deep of SubDirectorys, you've to filter out these and so you may lose time - in both solutions.

copy & rename files to other folder

I have some of log files formatted like this "name.log"
I would like to copy those from one folder to another folder like
xcopy /y "C:\Folder1" "D:\Folder2"
And i need to rename file with created date of original file (no copy file) so that the text file in Folder2 would be like "name yyyymmddhhmm.log" if some file has the same name (date of creation) it will be overwritten.
The code:
set Source=C:\Users\user1\Desktop\Folder1
set Dest=D:\Folder2
if not exist %Dest% md %Dest%
for /F %%a in ('dir /b "%Source%\*.txt"') do call :Sub %%a
goto :eof
:Sub
set "filename=%1"
for /F %%s in ("%Source%\%1") do if %%~zs==0 goto :eof
set "datepart="
FOR /F "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%filename%" ^| findstr "%filename%"') DO (
IF "%%c" neq "" SET "datepart=%%c%%a%%b%%d%%e"
)
FOR /F %%a IN ("%filename%") DO (
set "NewName=%%~na %datepart%%%~xa"
)
xcopy /y "%Source%\%filename%" "%Dest%\%NewName%*"
GOTO :EOF
The problem is that If I don't put the .bat in the same folder that origin files (Folder1),the files aren't change name. For example, if it is out, the files change name with old name and one white space.
The command windows tell me that it doesn't find the file when it get the creation date.
If I put the script into folder1 it works well.
On the other hand, if I execute the script with "Task Scheduler" I have the same problem. The files are copied but without date of creation.
What do I need to solve this problem?
#ECHO OFF
SETLOCAL
set Source=C:\Users\user1\Desktop\Folder1
set Dest=D:\Folder2
set "Source=u:\sourcedir\t w o"
set "Dest=u:\destdir"
if not exist "%Dest%" md "%Dest%"
for /F "delims=" %%k in ('dir /b "%Source%\*.log"') do call :Sub "%%k"
goto :eof
:Sub
SET "newname=%~1"
for /F "delims=" %%s in ("%Source%\%~1") do (if %%~zs==0 goto :eof
FOR /F "tokens=1-5 delims=/-: " %%a IN ('dir /tc "%Source%\%~1" ^| findstr "%~1"') DO (
IF "%%c" neq "" SET "newname=%%~ns %%c%%a%%b%%d%%e%%~xs"
)
)
ECHO(xcopy /y "%Source%\%~1" "%Dest%\%NewName%"
GOTO :EOF
The required XCOPY commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(XCOPY to XCOPY to actually copy the files. Append >nul to suppress report messages (eg. 1 file copied)
This may seem quite a radical change, but actually it really isn't.
First issue is that I overrode your directory settings with directories to suit my system. The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned. set /a can safely be used "quoteless".
Using quotes in the md command makes the procedure immune to "paths containing separators" - I test using spaces in paths and filenames because that appears to be a popular thing to do.
I changed the directory-scan metavariable from %%a to %%k to avoid confusion with the %%a in the subroutine. Your text says that you are starting with &.log files, but your filemask was *.txt so I changed it to *.log. Quoting the parameter delivered to :Sub means the procedure will receive the entire name of the file if it contains spaces.
Within the subroutine, it would appear that yowant no name-change if the %%c part from the dir/tc scan is empty. %~1 is the supplied filename minus the quotes.
The outer loop in %%s : I added delims= to cater for spaces in filenames and used %~1 in preference to %filename%
Within the %%s block, %%s refers to the file, so you can use %%s and its modified forms like %%~zs to refer to that file's characteristics - which unfortunately do not include create-date (%%~ts contains the last-update date - you may be able to use that in te following line rather than dir and findstr)
Then as #aschipfi suggested, include the source directory in the dir otherwise the dir takes place on the current directory.
FOR /F "tokens=1-5 delims=/-: " %%a IN ("%%~ts") DO (
should work for you if you can use last-update-date in place of create-date.
So - if %%c is not empty, set the new name to (the name part of the file in %%s)+space+the date string+(the extension in %%s)
And then do the xcopy - using the old name unless it was modified.

Rename text files based on multiple strings in their contents

Firstly, there are a couple of similar questions on here to this (Rename file based on file Content batch file being the one I have tried to work an answer from - but I have no real clue what I'm doing), however I cannot find anything that meets my exact needs, and this is my first real foray into batch programming so the syntax is fairly new to me.
The question:
I have several hundred text files, with different names, where the header is formatted like so:
"Event Type : Full Histogram"
"Serial Number : xxxxxx"
"Version : V 10.60-8.17 "
"File Name : W133FA0Z.580H"
"Histogram Start Time : 12:39:08"
"Histogram Start Date : 2014-04-11"
I would like if possible to create a batch file to rename all the files in the folder to the format of:
StartDate StartTime
so for this example:
2014-04-11 12:39:08
My problems lie in the fact I'm not sure how to actually point it to where to find the string if it was for just one line (I've tried editing the answers in the question I posted above). And, futhermore, I have no idea how to add a second bit of code to find the StartTime string and then append that to the StartDate.
Thanks in advance,
Chris
Here is a very efficient method.
#echo off
pushd "pathToYourFolderContainingFilesToRename"
for /f "tokens=1,3 delims=:" %%A in (
'findstr /bc:^"\"Histogram Start Date :" *.txt'
) do for /f delims^=^"^ %%C in (
"%%B"
) do for /f tokens^=4-6^ delims^=^":^ %%D in (
'findstr /bc:^"\"Histogram Start Time :" "%%A"'
) do ren "%%A" "%%C %%D.%%E.%%F.txt"
popd
The 1st loop serves two purposes. It establishes file names that contain the start date string, as well as also returning the date string for each file.
The 2nd loop strips out spaces and quotes from the date string.
The 3rd loop parses out the start time from the file.
The 2nd and 3rd loops have very awkward syntax to enable including a quote in the list of delimiters. The 2nd loop sets DELIMS to a quote and a space. The 3rd set DELIMS to quote, colon, and a space.
Assuming you JUST have file formatted like in your description in the working directory :
#echo off&cls
setlocal EnableDelayedExpansion
for %%x in (*.txt) do (
set /a $sw=1
for /f "skip=4 tokens=2-4 delims=:" %%a in ('type "%%x"') do (
if !$sw! equ 1 set $Time=%%a-%%b-%%c
if !$sw! equ 2 (
set $Date=%%a
call:DoRen !$Time:~1,-1! !$Date:~1,-1! %%~nx%%~xx)
set /a $sw+=1
)
)
exit/b
:DoRen
echo ren "%3" "%2 %1"
If the output is OK you can remove the echo
The following will get the output you want, where the output will look like 2014-04-11 123908.
#echo off
set file=test.txt
for /f "delims=: tokens=2-4" %%a in ('find "Time" %file%') do set ftime=%%a%%b%%c
for /f "delims=: tokens=2" %%a in ('find "Date" %file%') do set fdate=%%a
echo %fdate:~1,-1% %ftime:~1,-1%
If all the files are in the same directory, then you can simply do this in a another for loop.
#echo off
setLocal enableDelayedExpansion
for /f %%f in ('dir C:\whatever\path\*.txt /B') do (
for /f "delims=: tokens=2-4" %%a in ('find "Time" %%a') do set ftime=%%a%%b%%c
for /f "delims=: tokens=2" %%a in ('find "Date" %%a') do set fdate=%%a
ren "%%~a" "!fdate:~1,-1! !ftime:~1,-1!.txt"
)
This will rename all text files in a specified directory the date and time in their contents. Note that this does not account for text files that do not have the date and time in their contents. You can (and probably should) add that as you see fit.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
DEL incorrectformat.log 2>nul
DEL alreadyprocessed.log 2>nul
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN ('dir /b /a-d "%sourcedir%\*.txt" ') DO (
SET keepprocessing=Y
SET "newname="
FOR /f "tokens=1-5delims=:" %%b IN (
'TYPE "%sourcedir%\%%a"^|findstr /n /r "$" ') DO IF DEFINED keepprocessing (
IF %%b==1 IF NOT "%%~c"=="Event Type " SET "keepprocessing="&>>incorrectformat.log ECHO %%a
IF %%b==5 SET newname=%%d%%e%%f
IF %%b==6 (
SET "keepprocessing="
SET "newname=%%d!newname!.txt"
SET "newname=!newname:"=!"
SET "newname=!newname:~1!"
IF "!newname!"=="%%a" (>>alreadyprocessed.log ECHO(%%a) ELSE (ECHO REN "%sourcedir%\%%a" "!newname!")
)
)
)
GOTO :EOF
Here's my version.
You'd need to set the value of sourcedir to your target directory.
A list of files not matching the specified format is produced as incorrectformat.log
A list of already-processed files is produced as alreadyprocessed.log
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO REN to REN to actually rename the files.

Resources