I am working on renaming files that come from digital camera video recordings.
They output files in a generic incremental filename of which I do not need any information from. My folder structure is: x:\processing\01020304\VIDEO\0001.avi.
The filename I am trying to achieve would be for this example:
01-02-20121227-07h30m00s-03-04.avi
In this example, 01-02 is the first 4 numbers of the 01020304 folder. 20121227 is the date the video was created, with 07h30m00s as the ending time of the video, which is usually reported by the "last modified time". finally the 03-04 is the second half of the folder name used previously.
I'm a complete novice to writing batch files like this, but was unable to find any other examples similar enough to get myself started, so any help would be greatly appreciated.
edit:
so far I've got:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
:: Setup
set "xPath=c:\processing\01010101\VIDEO"
set "xFolder="
set "xDateCreated="
:: Parse Folder Name
for /f "tokens=3 delims=\" %%A in ("%xPath%") do set "xFolder=%%A"
:: Loop through Videos
pushd %xPath%
for /f "tokens=1,2,3,4,*" %%A in ('dir *.avi /T:W /4') do if exist "%%~fE" (
set "xDateCreated=%%~A %%~B %%~C"
echo %xFolder:~0,2%-%xFolder:~2,2%-!xDateCreated:~6,4!!xDateCreated:~0,2!!
xDateCreated:~3,2!-!xDateCreated:~11,2!h-!xDateCreated:~14,2!m-00s-%xFolder:~4,2%-%
xFolder:~6,2%%%~xE
)
popd
endlocal
pause
we're almost there, just missing the seconds, and if possible id like to change it so i do not have to supply the directory, but rather run it from the processing folder and check all 01010101, 02010101, etc directories..
Updated Answer
#echo off
setlocal EnableExtensions EnableDelayedExpansion
:: Create Empty Folder
rd /Q "%Temp%\Temp" 2>nul & mkdir "%Temp%\Temp"
:: Loop through Folders
pushd "xPath=x:\processing"
for /d %%D in (*) do call :Process "%%~fD"
popd
goto End
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Process <Parent>
:: Folder Name
set "xFolder=%~nx1"
:: Set Sub Folder
if not exist "%~1\VIDEO\" goto :eof
pushd "%~1\VIDEO"
:: Loop through Videos
for /f "delims=" %%A in ('dir *.avi /b') do if exist "%%~fA" (
set "xDateWritten=%%~tA"
set "xDateGMT=0000/00/00 00:00:00"
for /f "tokens=1,2" %%X in ('robocopy . "%Temp%\Temp" "%%~nxA" /TS /FP /NS /NC /NP /NJH /NJS /NDL /L') do set "xDateGMT=%%X %%Y"
rem Format = FF-FF-YYYYMMDD-HHh-MMm-SSs-FF-FF.ext
echo %xFolder:~0,2%-%xFolder:~2,2%-!xDateWritten:~6,4!!xDateWritten:~0,2!!xDateWritten:~3,2!-!xDateWritten:~11,2!h-!xDateWritten:~14,2!m-!xDateGMT:~17,2!s-%xFolder:~4,2%-%xFolder:~6,2%%%~xA
)
popd
goto :eof
:End
endlocal
pause
Since you changed the T:C to T:W I adjusted the script to just use the Last Written Date and I added the folder recursion.
When ready replace the echo line with this:
ren "%%~fA" "%xFolder:~0,2%-%xFolder:~2,2%-!xDateWritten:~6,4!!xDateWritten:~0,2!!xDateWritten:~3,2!-!xDateWritten:~11,2!h-!xDateWritten:~14,2!m-!xDateGMT:~17,2!s-%xFolder:~4,2%-%xFolder:~6,2%%%~xA"
Original & Edits
Well to keep the script simple I am basing the formatting strictly off the folders structure you posted. This is just a skeleton script to get you started. It works, but does not get the length of the video. The length can be calculated based on the information already retrieved, but I did not feel like doing date math right now. :)
#echo off
setlocal EnableExtensions EnableDelayedExpansion
:: Setup
rd /Q "%Temp%\Temp" & mkdir "%Temp%\Temp" 2>nul
set "xPath=x:\processing\01020304\VIDEO"
set "xFolder="
:: Parse Folder Name
for /f "tokens=3 delims=\" %%A in ("%xPath%") do set "xFolder=%%A"
:: Loop through Videos
pushd %xPath%
for /f "tokens=1,2,3,4,*" %%A in ('dir *.avi /T:C /4') do if exist "%%~fE" (
set "xDateWritten=%%~tE"
set "xDateCreated=%%~A %%~B %%~C"
set "xDateGMT=0000000000000000000"
for /f "tokens=1,2" %%X in ('robocopy . "%Temp%\Temp" "%%~E" /TS /FP /NS /NC /NP /NJH /NJS /NDL /L') do set "xDateGMT=%%X %%Y"
echo %xFolder:~0,2%-%xFolder:~2,2%-!xDateCreated:~6,4!!xDateCreated:~0,2!!xDateCreated:~3,2!-!xDateWritten:~11,2!h-!xDateWritten:~14,2!m-!xDateGMT:~17,2!s-%xFolder:~4,2%-%xFolder:~6,2%%%~xE
)
popd
endlocal
pause
Unfortunately, the t option and dir command do not provide the date resolution needed for seconds. To obtain the full last modified time stamp of the file you can use either the forfiles or robocopy commands.
rd /Q "%Temp%\Temp" 2>nul & mkdir "%Temp%\Temp" && robocopy . "%Temp%\Temp" *.avi /TS /FP /NS /NC /NP /NJH /NJS /NDL /L
NOTE: RoboCopy returns the time stamp of the file in GMT+0! It does not return the time stamp based upon the user's timezone settings. To determine which timezone you are, use tzutil /g.
See RoboCopy /? (Vista+ or XP Resource Kit)
forfiles /M *.avi /C "cmd /c echo #ftime"
See ForFile /? (Vista+)
Edit:
I updated the code to include the last written hour and minute into the file name. All that needs to be done is to add the rename command in the loop. To obtain the seconds for the time stamp from the files, either the robocopy or forfiles commands will have to be used.
Edit 2:
Added note about RoboCopy and the GMT+0 file time stamp and updated code to work with this limitation. Added the rd and mkdir to ensure that we have an empty folder, Added the for parse for the robocopy file timestamp, and added the xDateGMT variable. This should fully work now, if I have time later, I will clean it up a little more.
Edit 3:
Reformatted the answer to make it cleaner. See above Update section.
Related
Following is the directory that I use.
C:\test>dir /s /b /a:d
C:\test\A
C:\test\A\a
C:\test\A\b
C:\test\A\a\a
C:\test\A\a\b
C:\test\A\a\a\20160101
C:\test\A\a\a\20160816
C:\test\A\a\b\20160101
C:\test\A\a\b\20160816
C:\test\A\b\a
C:\test\A\b\b
C:\test\A\b\a\20160101
C:\test\A\b\a\20160816
C:\test\A\b\b\20160101
C:\test\A\b\b\20160816
Using dir /s /b /a:d gets all of folder directory.
How can I get the file list to go under 3 layer of test folder by batch file?
I would like to get the following list:
C:\test\A
C:\test\A\a
C:\test\A\b
C:\test\A\a\a
C:\test\A\a\b
C:\test\A\b\a
C:\test\A\b\b
#echo off
cls
for /f "delims=" %%I in ('dir /s /b /ad') do (
call :countAppr "%%~I"
)
exit /b
:countAppr
set "string=%~1"
set count=0
:again
set "oldstring=%string%"
set "string=%string:*\=%"
set /a count+=1
if not "%string%" == "%oldstring%" goto :again
if %count% leq 4 echo( %~1
exit /b
Explanation:
Loops thorough files
Count for the amount \ appears in the folder name
If less than or equal 4, return the folder name
To show folder only in the folder level, change leq to equ. The level deep can also be changed.
Note: Some of the script is copied and edited from Stephan's answer here.
One simple solution is to use the robocopy command. While intended for file copy operations, it includes a /L switch to request not to copy but to list. Adjusting the switches to remove non needed information you can use
robocopy . . /e /nfl /njh /njs /ns /lev:4 /l
This will recursively (/e) list (/l) all selected elements under the current folder, not showing file information (/nfl), without job header (/njh), without summary (/njs), without file/size counters (/ns) for a deep search of four levels (current folder plus the three required levels below)
The output of the robocopy command includes some tabs/spaces at the start of the line. If you need to remove them, you can use something like
for /f "tokens=*" %a in ('robocopy . . /e /nfl /njh /njs /ns /lev:4 /l') do echo %a
Or, from a batch file
for /f "tokens=*" %%a in ('robocopy . . /e /nfl /njh /njs /ns /lev:4 /l') do echo %%a
edited If robocopy usage is a problem (not available/allowed in your system), or you need (from comments) to limit the output to only the last level, you can use something like
#echo off
setlocal enableextensions disabledelayedexpansion
rem Retrieve folder from command line, default current folder
for /f "delims=" %%a in ("%~f1\.") do set "target=%%~fa"
echo ----------------------------------------------------------------------
rem Call subroutine searching for ALL folders up to 3 levels
call :treeDump target 3
echo ----------------------------------------------------------------------
rem Call subroutine searching for folders ONLY 3 levels deep
call :treeDump target 3 true
goto :eof
rem Recursive folder search
:treeDump targetVar maxLevel forceLevel
rem targetVar = name of variable containing the folder to iterate
rem maxLevel = how many levels to search under target
rem forceLevel = only show the last requested level
setlocal disabledelayedexpansion
rem Check we are not searching too deep
2>nul set /a "nextLevel=%~2-1", "1/(%~2+1)" || goto :eof
rem Retrieve folder to iterate
setlocal enabledelayedexpansion & for %%a in ("!%~1!") do endlocal & (
rem Determine if current level must be shown
if "%~3"=="" (
echo %%~fa
) else (
if %nextLevel% lss 0 echo %%~fa
)
rem If not at the last level, keep searching
if %nextLevel% geq 0 for /d %%b in ("%%~fa\*") do (
set "target=%%~fb"
call :treeDump target %nextLevel% "%~3"
)
)
goto :eof
It uses a recursive function that will iterate over the directories tree. For each folder found, if we are not at the required level, subfolders are enumerated and the function is called again for each of them.
I am looking to change the last modified time stamp of all my files and directories in "My documents". The reason is that all documents older than 3 months get deleted on the server I am using. This is just a trick to keep my documents as I often need them again after a longer period of time.
What I managed so far with the code below is to change the time stamp "last modified" of all files, including in the subdirectories. But it doesn't change the time stamp of the subdirectories themselves.
#echo off
for /f "delims=" %%a in ('dir /ad /b /s') do (
pushd "%%a"
copy /B /Y *.*+,,
popd
)
I got this piece of code after some research, but do not understand it fully...
I hope you guys can help
I have solved it with the following code.
As #aschipfl suggested, I created a random file and then immediately deleted it afterwards
#echo off
copy /B /Y *.*+,, >nul
echo. > randomfile.txt
if exist randomfile.txt del randomfile.txt /Q
for /f "delims=" %%a in ('dir /ad /b /s') do (
pushd "%%a"
copy /B /Y *.*+,, >nul
echo. > randomfile.txt
if exist randomfile.txt del randomfile.txt /Q
popd
)
cls
echo All files and folders updated %date% %time%
pause
I am a complete novice in batch programming but have found some great scripts in here that I tried modifying. I need the info on the last file modified in a directory. The script below gives me a file with info about file name and modification time. It searches through subdirectories too but seems to get stuck in a subdirectory instead of finding the newer file in the parent directory. I am not sure what could be wrong (as I only partly understand the code). Any suggestions from you smart guys in here?
Thanks in advance!
#echo off
setlocal
set srcDir=C:\Test
set lastmod=
pushd "%srcDir%"
for /f "tokens=*" %%a in ('dir *. * /b /od /s /a-d 2^>NUL') do set lastmod=%%a
if "%lastmod%"=="" echo Could not locate files.&goto :eof
for /d %%a in ("%lastmod%") do echo "%lastmod%", Modified date: %%~ta>"C:\Test\Details.txt"
This uses robocopy so it will only work on windows Vista and later. For it to work on XP you will need to get a copy of robocopy from a later OS or from resource kit.
No copy operation will really be made, but it will allow to retrieve a recursive file list with an adequated file stamp that can be sorted to find latest file.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
for /f "tokens=2,*" %%a in (
'robocopy "%folder%" "%folder%" "*" /s /is /nocopy /nc /ns /ts /fp /np /ndl /njh /njs /xjd /r:0 /w:0 /l ^| sort /r '
) do ( set "latest=%%b" & goto :done )
:done
for %%f in ("%latest%") do echo(%%~tf %%~ff
I have files with varying names...
Tim-01.jpg
Tim-02.jpg
Tim-03.jpg
jack-01.jpg
jack-02.jpg
jack-03.jpg etc in a single folder
I want to move all tim files into Tim folder and jack files to Jack folder etc.
Can it be done using .bat files ? If yes, please share the code for it.
Thank You.
#echo off
setlocal
set sourcedir=c:\sourcedir
for /f "tokens=1*delims=-" %%a in ('dir /b /a-d "%sourcedir%\*-*.*") do (
md "%sourcedir%\%%a" 2>nul
echo move "%sourcedir\%%a-%%b" "%sourcedir%\%%a\"
)
Note that the 2>nul suppresses error messages created when an attempt is made to recreate an existing directory
The MOVE is merely ECHOed. Remove the ECHO keyword to activae the move. It may also be prudent to append >nul to the MOVE statement to suppress the "1 file(s) moved" message.
As you may know, there are no arrays in Batch. So let's just use one.
#ECHO OFF &SETLOCAL
for /f "tokens=1*delims=-" %%a in ('dir /b /a-d *-*.jpg') do set "$%%a=%%a"
for /f "tokens=1*delims==" %%a in ('set $') do robocopy "%cd%" "%cd%\%%b" "%%b*" /mov /l
Remove /l from robocopy to make it working.
EDIT - Changed code to reduce the number of file moves. Now, all files with the same prefix get moved in one command.
#echo off
setlocal enableextensions
rem source of images
set "_dir=."
rem for each jpg with a dash in its name
for %%f in ("%_dir%\*-*.jpg") do (
rem if the file still exists (maybe it has been moved)
rem then split the file name with the dash as delimiter
if exist "%%~ff" for /F "tokens=1 delims=-" %%s in ("%%~nf") do (
rem and if we get a folder target, move the all the files
rem with same prefix to proper folder
if not "%%~s"=="" (
robocopy "%_dir%" "%_dir%\%%~s" "%%~s-*.jpg" /mov /njs /njh
)
)
)
endlocal
EDIT2 - Changed to adapt to comments
#echo off
setlocal enableextensions enabledelayedexpansion
rem source of images
set "_dir=."
rem for each jpg with a dash in its name
for %%f in ("%_dir%\*-??.jpg") do (
rem if the file still exists (maybe it has been moved)
if exist "%%~ff" (
rem get the filename without the 3 last characters
set "_target=%%~nf"
set "_target=!_target:~0,-3!"
rem and if we get a folder target, move the all the files
rem with same prefix to proper folder
if not "!_target!"=="" (
robocopy "%_dir%" "%_dir%\!_target!" "!_target!-??.jpg" /mov /njs /njh
)
)
)
endlocal
Here's my situation. I have a few hundred folders (under Windows XP),
each of which contain several .jpgs. The names of the folders all
got messed up when I accidentally selected all of the folders in the
process of renaming one of them.
What I'm setting out to do is write a DOS Batch script which will
iterate through each folder, determine the modification date of the
newest file within the directory & rename the folder to that date in
YYYY-MM-DD format. Hence:
Directory of C:\Work_Area\Messed_up_dir_name
07/11/2012 10:01 AM <DIR>
07/11/2012 10:01 AM <DIR>
03/10/2008 11:00 AM 176,640 image1.jpg
08/07/2007 02:27 PM 25,088 image2.jpg
04/12/2007 04:52 PM 132,608 image3.jpg
02/06/2007 06:11 PM 61,086 image4.jpg
Becomes "C:\Work_Area\2008-03-10\"
This is what I have written so far...
#echo off
REM ITERATE THROUGH EACH DIRECTORY
FOR /F "DELIMS==" %%d in ('DIR "%ROOT%" /AD /B') DO (
ECHO %%d
cd %%d
REM DETERMINE NEWEST FILE
FOR /F %%a in ('DIR /O:-D /B') DO #ECHO %%~ta
cd ..
REM echo Newest=%Newest%
REM move "%%f" "%Newest%"
pause
)
Obviously, the slashes in the date would need to be changed to another character
in order for this to be successful. If anyone could help me out with this, it
would be much appreciated!
This script will rename the folders of a directory tree whose root is specified in the 1st argument to the script (%1). I've written the script to satisfy the requirements specified in the 2nd comment to the question.
The script as written will actually echo the rename commands that would run. Simply remove the ECHO command from in front of REN when ready to rename for real.
At least one rename will fail if sibling folders have most recent modified files with the same time stamp.
Also the script cannot rename a folder that does not contain any files.
#echo off
setlocal disableDelayedExpansion
if "%~1" neq "" pushd %1
for /f "eol=: delims=" %%D in ('dir /s /b /ad ^| sort /r') do call :renameFolder "%%D"
exit /b
:renameFolder
pushd %1
for /f "eol=: delims=" %%F in ('dir /b /a-d /o-d') do (
for /f "tokens=1-4* delims=/: " %%A in ("%%~tF") do (
popd
echo ren %1 "%%C-%%A-%%B %%D.%%E"
exit /b
)
)