I need to generate lists of all files that has been created, modified and accessed respectively on a windows system.
I have found the command forfiles here http://technet.microsoft.com/sv-se/library/cc753551(v=ws.10).aspx but apparently this does not use the created and accessed timestamps, I need those also (in separate lists).
I have also looked into using the dir command but I have only found references to sorting and not filtering in the help sections.
Your question have some unclear details, so I made some assumptions.
The Batch file below create three separated text files: created.txt, modified.txt and accessed.txt, with the lists of the files in current folder; each list have the respective date in YYYYMMDDHHMMSS format followed by the file name, so it may be easily processed.
#echo off
setlocal DisableDelayedExpansion
for %%f in (created modified accessed) do if exist %%f.txt del %%f.txt
set "folder=%CD:~2%"
for /F "skip=1 tokens=1-3*" %%a in (
'"wmic datafile where (path='%folder:\=\\%\\') get InstallDate, LastModified,
LastAccessed, Name"'
) do (
for /F "delims=." %%A in ("%%a") do echo %%A %%d>> created.txt
for /F "delims=." %%B in ("%%b") do echo %%B %%d>> modified.txt
for /F "delims=." %%C in ("%%c") do echo %%C %%d>> accessed.txt
)
rem Process each list this way:
for /F "tokens=1*" %%a in (created.txt) do echo %%a - %%b
In the subject there was also "between dates" :) How about that?
forfiles doesn't allow to put 2 date conditions ('+' and '-').
I also have a problem with a date condition with unequalness in wmic.
for example:
wmic datafile where (path='%folder:\=\\\\%\\\\' and lastmodified ^> "20120713" and lastmodified ^< "20120714") get Name
returns nothing (I needed an escape ('^') before '<' and '>' to run the command).
wmic datafile where (path='%folder:\=\\\\%\\\\' and lastmodified ^> "20120713") get Name
returns only files modified after 20120714000000 (in the wmic notation).
Related
I have some files that I would like to sort through and keep the newest file.
I cannot do it by file attributes date modified or created, which I could do no problem.
Here is the naming convention of the files. FileABC_YYYYMMDD.txt
FileABC_20190201.txt
FileABC_20190125.txt
FileABC_20190118.txt
FileABC_20190111.txt
FileABC_20190104.txt
You can see that the date stamp is in the filename itself. These files are generated weekly. So I'd like to have a batch file loop through them and delete all but most currently dated file. I have really searched for how to do this best and I'm not finding much so I need ideas. I prefer a pure cmd solution but I'm open to powershell solutions as well.
What I am trying on my own is to parse out the date with...
#echo off
setlocal enabledelayedexpansion
for /f "tokens=* delims= " %%G IN ('dir/b /a-d "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName\FileABC_*.txt"') do (
set fileName=%%G
Set theDate=!fileName:~8,8!
echo !theDate!
)
Then I want to take those dates somehow from the results of the loop and do something like
if "%theDate%" GEQ "*****not sure what to put here*****" (
del *all the old files, also not sure what to put here*
)
How about this?
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do del %%i
If you just want to test it (see what it would delete) first, do:
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do echo %%i
If you do not care about the file dates but only the dates in the file names, you could do the following, given that the part FileABC is always the same and does not contain any _ on its own:
pushd "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName" && (
for /F "skip=1 delims= eol=|" %%F in ('
dir /B /A:-D "FileABC_????????.txt" ^
^| sort /R
') do (
del "%%F"
)
popd
)
Although sort /R does alphabetic sorting, this works because of your chosen date format, which ensures that alphabetic order equals alphanumeric one.
We just loop through the files, sorted by date in decending order, then skip the first file, now being the latest:
#for /f "skip=1" %%a in ('dir /b /o-d *.txt') do #echo #del %%a
Important!
This example will only echo the delete command as a safe measure so you do not delete files you should not have. To perform the actual delete, remove #echo from the line.
To understand more about the functions we used, run the following from cmd.exe
for /?
dir /?
As an additional option, just in case the filename prefix changes throughout and only the _YYYYMMDD.txt remains constant, you can still peform the task using that date as it is already alphabetically sortable.
Here's an example:
#Echo Off
Set "SrcDir=%UserProfile%\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName"
For /F "Delims==" %%A In ('Set $ 2^>Nul') Do Set "%%A="
Set "_="
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt 2^>Nul'
) Do Set "_=%%~nA" & Call Set "$%%_:~-8%%=%%A"
If Not Defined _ Exit /B
For /F "Tokens=1* Delims==" %%A In ('Set $ 2^>Nul') Do Set "_=%%B"
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt^|Find /V "%_%"'
) Do Del /A /F "%%A"
This uses the fact that the Set command will output variables in alphabetical order.
Lines 2 to 4 just define and undefine the variables we will be using.
Lines 5 and 6 is a single line split over two lines for readability. This will set variables using the last eight characters of the files basenames, to the value of the full filename.
Line 7 is included to exit the script, just in case no .txt files with a basename ending with an underscore followed by eight characters were found in the directory set at line 2.
Line 8 is the special one here, it outputs each variable and corresponding value in alphabetical order. The output is set to a variable, which overwrites itself until the loop ends. This means that the newest file, last one alphabetically, is held with the value of the file named with the newest date.
Lines 9 & 10 are once again a single line split over two for readability. This loops over all matching files in the directory again and uses the Find command to exclude outputting the one which matches that held in the variable as the file with the newest date. Each file output is simply deleted using the Del command.
Please note that this script assumes you only have a single file with each date, as you've only stated that the files are generated weekly.
I have file(s) in a folder with names like "223.DAT_2017010211315" I want to loop through all the files and rename them to like 223_2017010211315.DAT"
The closest I got to this requirement is as follows. I could just get the first token of the file name.
set "res=223.DAT_2017010211315"
for /f "tokens=1 delims=." %%i in ("%res%") do (set prefix=%%i)
echo %prefix%
pause
Could someone help me through this?
Let's start by iterating the file system. This should search the required files and show them
for %%f in ("*.dat_*") do echo %%f
Now, once we are able to find the files to process we need to separate the name and the extension of the files. That is an easy task as the for replaceable parameters (%%f in previous code) allow the usage of some modifiers to retrieve specific information of the referenced file (see for /? for a full list). We will use %%~nf (the name of the file referenced by %%f) and %%~xf (the extension of the file being referenced by %%f)
for %%f in ("*.dat_*") do echo %%~nf %%~xf
Once we have the two elements, we need to split the extension using the underscore as a delimiter. This will give us two tokens, left and right sides of the underscore. For this for /f is used to process the file extension.
for /f "tokens=1,2 delims=_" %%a in ("%%~xf") do echo %%a %%b
As we are requesting two tokens, the for /f will use the requested replaceable parameter %%a to store the first one, and will create an additional replaceable parameter %%b (next character) to store the second token.
%%~nf %%~xf
[.][................]
223.DAT_2017010211315 = %%f
^..^ ^...........^
%%a %%b
So, for each file in the list, execute the for /f to retrieve the needed information to execute the ren command.
for %%f in ("*.dat_*") do for /f "tokens=1,2 delims=_" %%a in ("%%~xf") do (
echo ren "%%f" "%%~nf_%%b%%a"
)
Note that for debugging purpouses, the ren command is not executed, only echoed to console to check the code behaviour. If the output is correct, remove the echo and run the code again.
#echo off
REM for every file matching the filter do:
for %%f in (*.dat_*) do (
REM disassemble into tree tokens, using . and _ as delimiters:
for /f "tokens=1,2,3 delims=._" %%a in ("%%~f") do (
REM re-assemble in different order:
echo %%a_%%c.%%b
)
)
Just to show an alternative way:
#echo off&setlocal enabledelayedexpansion
pushd "X:\path\to\folder"
for %%A in (*.dat_*) do (
set fname=%%A
Echo ren "%%A" "!fname:.DAT=!.DAT"
)
Popd
If output looks ok, remove the echo
Windows, Command Prompt, need to generate a .txt file output containing of all files from a big and complex dir tree with one (1) line for each files as:
CreationDateYYYYMMDD-HHMMSS, LastModifiedYYYYMMDD-HHMMSS, filesize[no K commas], filename.ext
for example:
20100101-174503, 20120202-191536, 1589567, myfile.ext
The list should not contain lines of dir name entries, etc., only filenames, even if the same file is present in more than once. Time in 24 hours format.
dir /s/t:c/t:w/-c > filelist.txt
command does not exactly works this way.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=c:\program files"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
FOR %%d IN (timewritten timecreated) DO SET "%%d="
FOR %%k IN (-d s h) DO (
IF NOT DEFINED timewritten FOR /f "tokens=1,2 delims= " %%d IN ('dir /tw %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timewritten=%%d %%e"
IF NOT DEFINED timecreated FOR /f "tokens=1,2 delims= " %%d IN ('dir /tc %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timecreated=%%d %%e"
)
ECHO !timecreated! !timewritten! %%~za %%~nxa
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
Interesting problem. This code processes it by
First, applying the standard directory-list for filenames on the tree from the relative root (%sourcedir%) to %%a
Using the full filename in %%a, set timewritten and timecreated from an ordinary dir list targeting the file in question.
It appeared that %%~ta didn't play nicely to extract the timestamp for hidden and system files, so I decided to build them from the ordinary dir listing with the appropriate t setting, specifically listing with /a-d, /as and /ah and filtering for the line which matched the filename, which seemed to extract the data appropriately.
I left the date/time in raw format. It should be an easy task to extract the various elements and construct the report in the format you want.
This question is a dupe of the SO post cmd dir /b/s plus date, but posting what worked for me:
#echo off
REM list files with timestamp
REM Filename first then timestamp
for /R %I in (*.*) do #echo %~dpnxI %~tI
#echo off
REM list files with timestamp
REM Timestamp first then name
for /R %I in (*.*) do #echo %~tI %~dpnxI
The above are the versions that you would directly paste into a command prompt.
If you want to use these in a batch file and log the output, you could do something like:
rem: Place the following in a batch file such as DirectoriesBareWithTS.cmd.
rem: As the first step in the batch file, net use to the directory or share you want the listing of
rem: Change to your target directory
Y:
for /R %%I in (*.mp4) do #echo %%~tI %%~dpnxI
Then you can pipe the output to a log file when you execute:
DirectoriesBareWithTS.cmd > C:\temp\GiantLongDirListing.log
You could then import that log into Excel.
I got something that has been given me some problems for a little while. I have a list of reports that are .csv files. The way they are organized is:
Call Details Report_1448937644342.csv
Call Details Report_1449662976507.csv
Call Details Report_1450293169999.csv
Initial Call Pricing By Archive Report_1448937621469.csv
Initial Call Pricing By Archive Report_1449662916869.csv
Initial Call Pricing By Archive Report_1450293146194.csv
Location Detail Report_1448937658179.csv
Location Detail Report_1449662949955.csv
Location Detail Report_1450293201330.csv
Location Summary Report_1448937672801.csv
Location Summary Report_1449662994508.csv
Location Summary Report_1450293231606.csv
StartStop (1).csv
StartStop (2).csv
StartStop (3).csv
StartStop.csv
Sensor (1).csv
Sensor (2).csv
Sensor (3).csv
So what I would need is something that I can copy the most recent of each report to a different directory while renaming it without the spaces or numbers (CallDetailsReport, IntialCallPricingByArchiveReport, etc.). So if I would run the batch file now it would take that directory of files, find Most recent of each report, copy and rename it to another directory.
I have tried to use the FOR command, but have had very little luck, the biggest problem I have is the number after the _ varies greatly, but it is always greater. I also thought that maybe I could narrow it down by the most recent files, but the endings always being different is kind of messing me up. I am hoping you guys can help.
I got this so far that gives me a list, but does not narrow it down to the most recent.
FOR %%G IN (Report1*.csv ) do #echo %%G
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
FOR /f "tokens=1*delims= " %%a IN (
'dir /b /a-d /o-d "%sourcedir%\*.csv" '
) DO (
IF "%%b" neq "" IF NOT EXIST "%destdir%\%%a" COPY "%sourcedir%\%%a %%b" "%destdir%\%%a" >nul
)
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
Read the source directory in basic form without directorynames and in reverse-date order so the latest files matching the mask appear first. Split the filename into two using the space as a separator. If the second part is not empty (ie the space exists) test for the presence of a file thefirstpart in the destination directory and perform the copy if it doesn't exist - consequently it will be copied from the first (latest) file found and not be overwritten.
Adjustments to suit your actual requirement would be in your court.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
FOR /f "tokens=1*delims=_" %%a IN (
'dir /b /a-d /o-d "%sourcedir%\*.csv" '
) DO (
IF "%%b" equ "" (
FOR /f "tokens=1*delims= " %%j IN ("%%a") DO (
IF "%%k" neq "" IF NOT EXIST "%destdir%\%%j" COPY "%sourcedir%\%%a" "%destdir%\%%j"
)
) ELSE (
IF NOT EXIST "%destdir%\%%a" COPY "%sourcedir%\%%a_%%b" "%destdir%\%%a"
)
)
GOTO :EOF
Revision to suit realistic filenames.
Try this:
#echo off
set max=0
for /f "tokens=2 delims=_." %%n in ('dir /b Report1*.csv') do (
if %%n GTR !max! set max=%%n
)
copy "Report1 Number_%max%.csv" otherdir\Report1.csv
Original Answer (based on the original question)
Assuming that the greatest numbers denote the most recent items, the following batch script does what you are looking for:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Set up source and destination directories here:
set "SOURCE=D:\source"
set "DESTIN=D:\destin"
for /F "tokens=1,2,3,4 delims=._ " %%I in ('
2^> nul dir /B /A:-D "%SOURCE%\*.csv" ^| ^
findstr /I /R /C:"^Report[0-9][0-9]* Number_[0-9][0-9]*.csv$"
') do (
set "REPORT=%%I"
set "REPORT=0000000!REPORT:*Report=!"
set "NUMBER=0000000%%K"
set "ITEM-!REPORT:~-8!=%%I.%%L"
set "ITEMS-!REPORT:~-8!-!NUMBER:~-8!=%%I %%J_%%K.%%L"
)
for /F "tokens=2,3 delims=-=" %%I in ('
2^> nul set ITEM-
') do (
for /F "tokens=2 delims==" %%X in ('
2^> nul set ITEMS-%%I-
') do (
set "RECENT=%%X"
)
> nul copy /Y /B "%SOURCE%\!RECENT!" "%DESTIN%\%%J"
)
endlocal
exit /B
Basically this approach builds up array-like variables ITEM- and ITEMS- that hold the numbers in the file names padded with leading zeros to consist of 8 digits, then use set to sort the items alphabetically and retrieve the most recent item. Because of the padding, alphabetic sorting results in the same order as alphanumeric sorting.
Both of these variables are set up in the first for /F loop, which enumerates all the applicable items using dir /B /A:-D "*.csv" | findstr /I /R /C:"^Report[0-9][0-9]* Number_[0-9][0-9]*.csv$". findstr is used to filter the files, because dir cannot so that in the same grade of detail. The variable names contain the zero-padded numbers for proper sorting. The variable values are the original file names (ITEMS-) and the new file names (ITEM-).
The second for /F loop parses the output of set ITEM-, which walks through all the first numbers after the word Report. This loop nests another one, iterating through the output of set ITEMS-, which holds both numbers in the file names. The inner loop stores the current item in variable RECENT and overwrites its value each time. Due to the sort order, the greatest number and therefore the most recent item is stored in RECENT. The outer loop is then actually copying the relative file.
Relying on the sample files you provided, the two arrays will hold the following data:
ITEM- (sorted):
ITEM-00000001=Report1.csv
ITEM-00000002=Report2.csv
ITEM-00000003=Report3.csv
ITEMS- (sorted):
ITEMS-00000001-00000123=Report1 Number_123.csv
ITEMS-00000001-00000126=Report1 Number_126.csv
ITEMS-00000001-00000133=Report1 Number_133.csv
ITEMS-00000002-00000123=Report2 Number_123.csv
ITEMS-00000002-00000126=Report2 Number_126.csv
ITEMS-00000002-00000133=Report2 Number_133.csv
ITEMS-00000003-00000123=Report3 Number_123.csv
ITEMS-00000003-00000126=Report3 Number_126.csv
ITEMS-00000003-00000133=Report3 Number_133.csv
Updated Answer (based on the revised question)
After you changed your original requirements intensively in the most recent revision of your question, I have reworked the script extensively and came up with the following two scripts, each handling a certain name pattern of your *.csv report files. Both scripts rely on a temporary file which is used for appropriate sorting using the sort command, to get the correct items with the greatest numbers:
This script handles all your report files that have a report name, an underscore _ and an index number in their file names.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Set up source and destination directories here:
set "SOURCE=D:\source"
set "DESTIN=D:\destin"
> "%~dpn0.tmp" (
for /F "tokens=1,2 delims=_" %%I in ('
2^> nul dir /B /A:-D "%SOURCE%\*.csv" ^| ^
findstr /I /R /C:"^[^_][^_]*_[0-9][0-9]*.csv$"
') do (
set "REPORT=%%I"
set "NUMBER=00000000000000000000000%%~nJ"
setlocal EnableDelayedExpansion
echo(!REPORT!^|!NUMBER:~-24!^|!REPORT!_%%J
endlocal
)
)
set "FORMER="
< "%~dpn0.tmp" (
for /F "tokens=1,3 delims=|" %%I in ('
sort /R
') do (
set "REPORT=%%I"
set "ORNAME=%%J"
setlocal EnableDelayedExpansion
if /I not "!REPORT!"=="!FORMER!" (
> nul copy /Y /B "%SOURCE%\!ORNAME!" "%DESTIN%\!REPORT: =!%%~xJ"
)
endlocal
set "FORMER=%%I"
)
)
del /Q "%~dpn0.tmp"
endlocal
exit /B
The related temporary file contains the following unsorted data, based on your sample files:
Call Details Report|000000000001448937644342|Call Details Report_1448937644342.csv
Call Details Report|000000000001449662976507|Call Details Report_1449662976507.csv
Call Details Report|000000000001450293169999|Call Details Report_1450293169999.csv
Initial Call Pricing By Archive Report|000000000001448937621469|Initial Call Pricing By Archive Report_1448937621469.csv
Initial Call Pricing By Archive Report|000000000001449662916869|Initial Call Pricing By Archive Report_1449662916869.csv
Initial Call Pricing By Archive Report|000000000001450293146194|Initial Call Pricing By Archive Report_1450293146194.csv
Location Detail Report|000000000001448937658179|Location Detail Report_1448937658179.csv
Location Detail Report|000000000001449662949955|Location Detail Report_1449662949955.csv
Location Detail Report|000000000001450293201330|Location Detail Report_1450293201330.csv
Location Summary Report|000000000001448937672801|Location Summary Report_1448937672801.csv
Location Summary Report|000000000001449662994508|Location Summary Report_1449662994508.csv
Location Summary Report|000000000001450293231606|Location Summary Report_1450293231606.csv
There data is then sorted with sort /R, where /R defines reverse sort order. The first |-delimited field contains the report name, the second field the zero-padded index number and the third one the original file name. Only such lines are used for copying which hold a report name different to the previous line.
This script handles all your report files that have a report name, a SPACE, a (, an index number and a ) in their file names. It even handles files that do not contain an index number but a report name only in their file names, where they are treated as having an index of 0.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Set up source and destination directories here:
set "SOURCE=D:\source"
set "DESTIN=D:\destin"
> "%~dpn0.tmp" (
for /F "tokens=1,2,3 delims=()" %%I in ('
2^> nul dir /B /A:-D "%SOURCE%\*.csv" ^| ^
findstr /I /R /C:"^[^()]*[^()0-9].csv$" /C:"^[^()][^()]* ([0-9][0-9]*).csv$"
') do (
if "%%J"=="" (
set "REPORT=%%~nI"
set "NUMBER=000000000000000000000000"
setlocal EnableDelayedExpansion
echo(!REPORT!^|!NUMBER:~-24!^|!REPORT!%%~xI
endlocal
) else (
set "REPORT=%%I"
set "NUMBER=00000000000000000000000%%J"
setlocal EnableDelayedExpansion
echo(!REPORT:~,-1!^|!NUMBER:~-24!^|!REPORT!^(%%J^)%%K
endlocal
)
)
)
set "FORMER="
< "%~dpn0.tmp" (
for /F "tokens=1,3 delims=|" %%I in ('
sort /R
') do (
set "REPORT=%%I"
set "ORNAME=%%J"
setlocal EnableDelayedExpansion
if /I not "!REPORT!"=="!FORMER!" (
> nul copy /Y /B "%SOURCE%\!ORNAME!" "%DESTIN%\!REPORT: =!%%~xJ"
)
endlocal
set "FORMER=%%I"
)
)
del /Q "%~dpn0.tmp"
endlocal
exit /B
The related temporary file contains the following unsorted data, based on your sample files:
Sensor|000000000000000000000001|Sensor (1).csv
Sensor|000000000000000000000002|Sensor (2).csv
Sensor|000000000000000000000003|Sensor (3).csv
StartStop|000000000000000000000001|StartStop (1).csv
StartStop|000000000000000000000002|StartStop (2).csv
StartStop|000000000000000000000003|StartStop (3).csv
StartStop|000000000000000000000000|StartStop.csv
The sorting technique is the same as for the other script.
In order to get all the report files you want, you need to execute both scripts.
I want to use dir command and have filename as 1st column, creation date time as 2nd column and modified date time as 3rd column.
How could I achieve this?
http://www.computerhope.com/dirhlp.htm
This shows /T might be used but not sure how to use it because dir /TCAW doesn't list the format I need.
As Christopher Painter says, the DIR command cannot do this directly.
But there is a simple command line one liner that displays your information without header or footer info. This command lists only files. It works as long as your locality displays time stamps using 3 space delimited components. For example, my U.S. time stamps display as mm/dd/yyyy hh:mm:ss am.
for /f "tokens=1-4*" %A in ('dir /a-d /tc^|findstr "^[0-9]"') do #echo %E %A %B %C %~tE
Change /a-d to /a if you want to include directories. Or simply remove /a-d entirely if you want both files and directories but you want to exclude hidden and system files/directories.
Here is the same command in a nicely formatted batch script:
#echo off
for /f "tokens=1-4*" %%A in (
'dir /a-d /tc^|findstr "^[0-9]"'
) do echo %%E %%A %%B %%C %%~tE
I don't like the output format with the file name in the front because the width of the name varies - it is hard to read the output because the columns don't line up. I prefer to put the file name at the end:
#echo off
for /f "tokens=1-4*" %%A in (
'dir /a-d /tc^|findstr "^[0-9]"'
) do echo %%A %%B %%C %%~tE %%E
DIR doesn't support what you are trying to do. the /T:Fileld ID can only show one set of time information at a time. I'm not sure what you are trying to do but I see you have some C# experience. You could write your only console app that outputs the way you out and call that instead.
# ECHO OFF
(FOR /f "delims=" %%a IN ('dir /b /a-d') DO (
FOR /f "tokens=1-3*" %%x IN ('dir /a-d /tc "%%~a"^|findstr "^[0-9]"') DO (
ECHO "%%a",%%~ta,%%x %%y %%z
)
)) > DIR.txt
TYPE DIR.txt
the answer in refered to : Windows batch file to create csv list of file and dates