Windows batch file renaming via reordering/manipulating current name - windows

I have a large amount of files in multiple folders, the file name format is:
FILE DESCRIPTION_MM DD YYYY_F_XXXXX.EXTENSION
The FILE DESCRIPTION is a variable amount of characters. XXXXX is a variable amount of characters as well. The extension is either pdf, doc or docx. The delimiter to be used is the first instance of _. Example:
Foo File_01 01 2016_F_Bar.pdf
I need to rename each file by reordering the Date to the front. Instead of the current format, it needs to be
MM DD YYYY_FILE DESCRIPTION_F_XXXXX.EXTENSION".
Thus I need to cut out DATE and the 2nd instance of _ and move it to the front of the filename. This amounts to 11 characters in total including the _.
The extension needs to be unchanged. Using the above example:
01 01 2016_Foo File_01 01 2016_F_Bar.pdf
Also I only want to rename the files in the format "FILE DESCRIPTION_MM DD YYYY_F_XXXXX.EXTENSION" ignoring all other cases in which files are already formatted with the DATE in the front and cases where there is no DATE.
Any help would be greatly appreciated!

Give this a try on some test data
#echo off
FOR /F "delims=" %%G IN ('dir /a-d /b /s *_*_*.pdf *_*_*.doc *_*_*.docx ^|findstr /R /C:".*_[0-9][0-9] [0-9][0-9] [0-9][0-9][0-9][0-9]_F_.*\."') DO (
FOR /F "TOKENS=1,2* delims=_" %%H IN ("%%~nxG") DO rename "%%~G" "%%~I_%%~H_%%~J"
)

Related

Batch script to read numerical part of file and rename with next higher integer

I have a file, such as -
foofile_1.ext
A script should read the numerical part of the file, and then rename the file with the next integer, i.e., after execution, the file name should be
foofile_2.ext
I can do it with a C++ / c application or even in bash but not sure how to write a batch script to perform this rename. The filename before the _ isn't going to change, and _ will aaways appear in the same position within the filename.
I can strip the filename to _, but recognizing the numerical is an implementation I am not familiar with. Once I recognize the numerical, I can increment it and rename the file.
Something to consider is that renaming foofile_1.ext to foofile_2.ext will fail should foofile_2.ext already exist. One way to get around it is to rename in descending numerical order, I posted an answer like that before on SO.
I am however not going to post the same answer here, nor link that answer. I will however show one other method:
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,*delims=_" %%i in ('dir /b /a-d "*_*.ext"') do (
echo %%~nj | findstr /R /V /C:"[A-Z]">nul && (
set /a numeric=%%~nj+1
ren "%%~i_%%~j" "%%~i_-hld-!numeric!%%~xj"
)
)
for /f "delims=" %%f in ('dir /b /a-d "*_-hld-*.ext"') do (
set "name=%%~f"
ren "%%~f" !name:-hld-=!
)
Considering that your input is as you said and does not contain earlier _'s anywhere. This will just take each file with the *_*.ext format. We split by the _ into two tokened metavaiables (%%i and %%j) We take the numeric value and increment by one, then rejoin %%i which is pre _. This however is where the problem comes when the file you are trying to rename to exists, so for that, first we test if %%~nj does not have Alphabetical characters only, using findstr (not doing special characters in this free code) Secondly we give a temporary addition to the name to prevent name clashing.
Once we are done, we simply do a rename on all the files containing the _-hld- temp inclusion.

append file date to file name using cmd

Hi I'd like to create a bat file to rename files using the cmd. Say a friend and I went on vacation together. We have put all our pictures together and I now want to rename all the pictures in a sequence.
Say I selected the following pictures:
mypicture_3435.jpg (file date = 01 Jan 2015 10:00)
mypicture_3465.jpg (file date = 04 Jan 2015 12:00)
myfriendspicture_2221.jpg (file date = 03 Jan 2015 12:00)
myfriendspicture_2226.jpg (file date = 04 Jan 2015 11:00)
I would like to get the following output:
ourvacation_01.jpg [mypicture_3435.jpg (file date = 01 Jan 2015
10:00)]
ourvacation_02.jpg [myfriendspicture_2221.jpg (file date = 03
Jan 2015 12:00)]
ourvacation_03.jpg [myfriendspicture_2226.jpg (file
date = 04 Jan 2015 11:00)]
ourvacation_04.jpg [mypicture_3465.jpg
(file date = 04 Jan 2015 12:00)]
This is easy to do with specific software such as acdsee or even with Windows' image browser. But I would like to do it using the command promt. (I teach mathematics in a school and I would like to use this as a programming example).
I tried the follwing script and it worked:
#echo off
setlocal EnableDelayedExpansion
set i=0
for %%a in (*.jpg) do (
set /a i+=1
ren "%%a" "!i!.new"
)
ren *.new *.jpg
But it renamed the files like this:
myfriendspicture_2221.jpg becomes 1.jpg
myfriendspicture_2226.jpg becomes 2.jpg
mypicture_3435.jpg becomes 3.jpg
mypicture_3465.jpg becomes 4.jpg
So the problems are:
They do not keep a chronological sequence.
If I have say 11 items, and sort them by name, the sequence runs 1, 10, 11, 2, 3, 4...
I tried to run dir /od before I rename, but it didn't work, the sequence runs according to the file name.
All the strings I have found regarding this issue append the current date and time to the file name, but not the file date and time to it's own name.
I couldn't find a way to add a leading 0 or 00 to the sequence so that the file name and chronological order match.
Thank you very much in advance for the help.
I tried to run dir /od before I rename, but it didn't work, the sequence runs according to the file name.
Did you simply run dir /od and then for %%a in (*.jpg)? How did you plan to capture the output of dir /od to make it useful, rather than just dumping it to stdout?
Whenever you want to capture the output of a command, use a for /f loop. You should combine the two commands like this:
for /f "delims=" %%I in ('dir /b /o:d *.jpg') do stuff.
Next issue: zero left padding the file names. Can we assume you won't have more than 10,000 pics from your vacation? Then just prepend four zeros to your generated filename, then use the right-most 4 characters to determine the base name of your pics.
#echo off
setlocal enabledelayedexpansion
set /a seq=10001
for /f "delims=" %%I in ('dir /b /o:d *.jpg') do (
rem :: remove the "echo" when you are ready to rename
echo ren "%%~I" "ourvacation_!seq:~-4!.jpg"
set /a seq += 1
)
The result will look a little something like this:
C:\Users\me\Desktop>test.bat
ren "avatar65929_2.jpg" "ourvacation_0001.jpg"
ren "IMG_20140621_190332.jpg" "ourvacation_0002.jpg"
ren "funny-Finding-Neverland-scene-Explorer.jpg" "ourvacation_0003.jpg"
ren "5DFPwMa.jpg" "ourvacation_0004.jpg"
ren "funny-root-math-equation.jpg" "ourvacation_0005.jpg"
ren "196889_145889312230730_1041953273_n.jpg" "ourvacation_0006.jpg"
ren "0001-cf72d77a-509ac348-b92c-fe8af7d2.jpg" "ourvacation_0007.jpg"
ren "IMG_20141230_191526.jpg" "ourvacation_0008.jpg"
ren "20150120_142150.jpg" "ourvacation_0009.jpg"
ren "20150120_145223.jpg" "ourvacation_0010.jpg"

Renaming a batch file and keeping part of the filename

I've seen plenty of posts on similar requests but I can't quite find one that suits what I am trying to do. It is fairly simple but I cannot seem to get it.
ren FILE??.txt FILE%Year%%Month%%Day%??.txt
copy FILE%Year%%Month%%Day%??.txt C:\Users\me\Desktop\Batch\renamed\achod%Year%%Month%%Day%??.txt
I cannot get the script to keep the '??' which represents random characters the first file may have.
Any help is appreciated.
You won't be able to rename files directly using a wildcard character. Instead you need to locate all the applicable files and then rename each.
The script below works under the assumptions of your question/comments:
File name is 6 chars long.
Only the last 2 chars are interchangeable.
Of course, the script could be very easily adapted to accomodate other settings but this does just as you requested.
SETLOCAL EnableDelayedExpansion
REM Set your Year, Month, Day variable values here.
REM They will be used for file renaming.
...
CD "C:\Path\To\Files"
FOR /F "usebackq tokens=* delims=" %%A IN (`DIR "File??.txt" /B /A:-D`) DO (
REM Extract the last 2 chars of the file name.
SET FileName=%%~nA
SET First4=!FileName:~0,4!
SET Last2=!FileName:~-2!
REM Rename the file, inserting the new data.
RENAME "%%A" "!First4!%Year%%Month%%Day%!Last2!%%~xA"
)
ENDLOCAL

Windows Shell Command to Show File Name and Last Access Time

I am trying to write a Windows command to list files and their last access times, sorted by access time.
I have used
dir [directory] /O:D /T:A /S /B > output.txt
This outputs the files in directory and sub directories in order by their last access time; however I also need it to output the last access time as well. How is this accomplished?
from within a batch file:
>output.txt (
for /f "delims=" %%F in ('dir /o:d /t:a /s /b "c:\myPath\*"') #echo %%~tF %%F
)
However, there are some things you need to be aware of:
The files are sorted by access timestamp within a directory. It does not sort by access timestamp across all the directories. Your original code has the same problem. To sort accross directories requires parsing the access timestamp and converting it into a string that will sort chronologically when ordered via SORT. Something like "yyyy-mm-dd hh24:mm". Even that is not particularly good because you don't have access to the seconds. You could use WMIC DATAFILE to list file names with last access timestamps at a sub-second level. But why bother, considering that...
The last access timestamp maintained by Windows is not reliable! There are many situations whereby an application can read a file and yet the last access timestamp is not updated. I've seen some reference material somewhere that talks about that, but I don't remember where.
If you still think you want to get a list of files sorted by last access timestamp for an entire folder hierarchy, then the following will work. Assume you want to list all files under "c:\test\"
wmic datafile where "drive='c:' and path like '\\test\\%'" get name, lastaccessed | sort
The timestamp will have the format YYYYMMDDhhmmssddddddZZZZ where
YYYY = year
MM = month
DD = day
hh = hour (24 hour format)
mm = minutes
ss = seconds
dddddd = micro seconds
ZZZZ = timezone, expressed as minutes difference from GMT (the 1st character is the sign)
EDIT
The wildcard search in WMIC causes terrible performance. Here is a version that iterates through all the folders in the root hierarchy, running WMIC against each specific folder (no wildcard). It has decent performance.
#echo off
setlocal disableDelayedExpansion
set "root=c:\test"
set "output=output.txt"
set "tempFile=%temp%\dir_ts_%random%.txt"
(
for /d /r "%root%" %%F in (.) do (
set "folder=%%~pnxF\"
set "drive=%%~dF"
setlocal enableDelayedExpansion
2>nul wmic datafile where "drive='!drive!' and path='!folder:\=\\!'" get name, lastaccessed|findstr /brc:[0-9]
endlocal
)
) >"%tempFile%
sort "%tempFile%" >"%output%"
del "%tempFile%"

Batch file to move files by date modified

I have written a batch file, which creates empty folders for each date. My next task is to create another batch file, which moves each file in a directory, into the relevant date folder, based on their date modified. I have read numerous forums and articles on how I can achieve this, but with my limited batch file knowledge, I just cannot seem to get it to work. The code I currently have is shown below, though this does not seem to pull in the date modified. Any help is much appreciated!
SET directory="\directory\path\archive"
FOR /f %%a in ('dir /b "%directory%"') do (
SET fdate=%%~Ta
MOVE "%directory%\%%a" "%directory%\%fdate%"
Until you provide more info as to format of dates, I can't give a definitive answer. But I can show you how I would do it on my machine.
I use yyyy-mm-dd format within file and folder names, so December 13, 2011 would be 2011-12-13. My machine uses mm/dd/yyyy format for dates (12/13/2011). So I would need to translate the %%~tF output from 12/13/2011 into 2011-12-13. Note - / cannot be used used in file or folder names.
So this code would do what you want on my machine:
set "source=\directory\path\archive"
set "targetRoot=\directory\path\archive"
for %%F in ("%source%\*") do (
for /f "tokens=1,2,3 delims=/ " %%A in ("%%~tF") do (
move "%%~fF" "%targetRoot%\%%C-%%A-%%B"
)
)
Addendum - Question in comment asks for method to left pad a number with zeros for dir creation. I see two easy choices. (This really should be a different question)
This first method is simple but tedious and not practical as a general solution
for %%A in (01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) do ...
The second method is a general solution. Since your assignment is within parentheses, you need to use delayed expansion.
setlocal enableDelayedExpansion
for /l %%A in (1 1 31) do (
set "day=0%%A"
set "day=!day:~-2!
...
)
You increase the number of leading zeros by adding more 0 to the front and then increasing the number of characters you preserve in the substring operation.
BUT - why prepopulate the directories? Your strategy will add directory days that don't exist in the calendar, plus you are likely to have many unused folders for which no files were modified on that day. Better to create the folders only as needed. Then the 0 padding is already done for you, and no unneeded folders are created.
set "source=\directory\path\archive"
set "targetRoot=\directory\path\archive"
for %%F in ("%source%\*") do (
for /f "tokens=1,2,3 delims=/ " %%A in ("%%~tF") do (
if not exist "%targetRoot%\%%C\%%A\%%B" mkdir "%targetRoot%\%%C\%%A\%%B"
move "%%~fF" "%targetRoot%\%%C\%%A\%%B"
)
)
My answer is a simple FOR loop who check all files in current directory and take date from eachone file. Create a folder in format yyyy\yyyy-mm and move file into it.
#echo off
rem not %var% but !var! give us access to internal loop variable value with enabledelayedexpansion.
setlocal enabledelayedexpansion
FOR %%V IN (*.*) DO (
SET filedate=%%~tV
rem echo !filedate!
SET fileyear=!filedate:~6,4!
rem echo !fileyear!
SET filemonth=!filedate:~3,2!
rem echo !filemonth!
rem create directory as yyyy\yyyy-MM
mkdir !fileyear!\!fileyear!-!filemonth! 2>nul
echo move %%V !fileyear!\!fileyear!-!filemonth!\
move %%V !fileyear!\!fileyear!-!filemonth!\ >nul
)
TIP: The filemonth and fileyear variable probably should have other numbers to cut proper yyyy/mm for your country/region timestamp.
TIP: This FOR move the script itself to into one of subdirectory, I run it as Windows Shortcut with enter a Location Path - then this script run in proper place.

Resources