Link to home
Start Free TrialLog in
Avatar of Luis Diaz
Luis DiazFlag for Colombia

asked on

Windows batch: count files with /d and /s options

Hello experts,
I have the following batch which allows me to count files on specific folder:
@echo off
setlocal enableextensions
set count=0
for %%x in ("C:\Temp") do set /a count+=1
echo Number of csv files: %count%
endlocal
pause

Open in new window


I was wondering how to put:
-/d option to specify files with a date modified older than 30 days
-/s option to proceed recursively

If you have questions, please contact me.
Thank you for your help.
Avatar of NVIT
NVIT
Flag of United States of America image

@echo off
setlocal enableextensions

set FNPath=c:\temp
set FNPatt=*.csv
set nDaysOld=30

echo All %FNPath%\%FNPatt% files...
set count=0
for /r "%FNPath%" %%x in (%FNPatt%) do set /a count+=1
echo Number of %FNPatt% files: %count%

echo.
echo %FNPath%\%FNPatt% files %nDaysOld% or more days old...
set count=0
for /f %%g in ('forfiles /D -%nDaysOld% /p "%FNPath%" /m %FNPatt%') do @set /a count+=1
echo Number of %FNPatt% files: %count%

pause

Open in new window

Avatar of Luis Diaz

ASKER

Thank you.
Possible to have /r option as flag parameter.
R=
No recursive to apply
R=Y
Recursive to apply
Your fastest and most effective method to do this is to leverage Robocopy.

Forfiles is slow and has some issues when working with date-times that Microsoft has never fixed.

For these reasosn, I usually do date comparisons of this sort using Robocopy.

When doing file counts DIR and Robocopy are much faster at returning a result than a loop is and in some cases, you can just use FIND to get exactly the info you want avoiding a loop entirely if you don't need to save the data for later.

I've amended your example script to utilize Robocopy and do either recursive or nonrecursive counts of files.


@(
  ECHO OFF
  SETLOCAL EnableExtensions EnableDelayedExpansion
  SET "_FileCount="
  SET "_CountPath=c:\Temp"
  SET "_EmptyPath=c:\Empty"
  SET  "_FileGlob=*.csv"
  SET "_MinAge=/MinAge:30"
  SET "_Recurse=/S"
  SET "_RoboCopyCMD=ROBOCOPY "!_CountPath!" "!_EmptyPath!" !_FileGlob! /L /NS /NC /NFL /NDL /NP /NJH !_Recurse! !_MinAge!"
)

FOR /F "Tokens=4" %%A IN ('%_RoboCopyCMD% ^| FIND /I "Files : "') DO (
  SET "_FileCount=%%A"
  ECHO.Files="%%A"
)

ECHO.Number of csv files: %_FileCount%
ENDLOCAL
PAUSE

Open in new window

Note, I had tprushout, if you want to remove  recurse set it =" same with min age
Avatar of Bill Prew
Bill Prew

If you want a pure BAT approach this should work:

@echo off
setlocal EnableDelayedExpansion

REM Define base for folders, and days to find newer files than
Set BaseDir=c:\temp
set DaysToFind=30

REM Get current date in MM/DD/YYYY format
set Today=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
  if not defined LocalDateTime (
    set LocalDateTime=%%A
    set Today=!LocalDateTime:~4,2!/!LocalDateTime:~6,2!/!LocalDateTime:~0,4!
  )
)

REM Convert todays date to julian for age checks
call :jDate jToday %Today%

set count=0
REM Process all Files in the directory, count if newer than days specified
for /r "%BaseDir%" %%A in ("*.*") do (
  call :jDate jFile %%~tA
  set /A FileAge = !jToday! - !jFile!
  if !FileAge! LEQ %DaysToFind% (
    set /a count+=1
  )
)

REM Display files found
echo Number of csv files: %count%

REM Done
exit /b

REM Subroutine to calculate julian date
:jDate [return-variable] [date-string(MM/DD/YYYY)]
  set DateStr=%~2
  set yy=%DateStr:~6,4%
  set /A mm=1%DateStr:~0,2%-100
  set /A dd=1%DateStr:~3,2%-100
  set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
  set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
  exit /b

Open in new window


»bp
Thank you Ben for this proposal.
I have a little issue with this because I need to create C:\empty folder manually and then run the count.
Why not adding a mkdir withing the reference folder to loop and once it is finished rmdir?
Thank you for your help.
Thank you Bill for this proposal.
I have the following error message:
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).

Open in new window

@Louis, yes! I just didn't have time before Ieft, I had to rush out
Odd, I did test it here and didn't get any errors.  You will probably need to run it with ECHO ON and then post up some of the lines that it displays before and after one of those error lines.


»bp
You could do this with Swiss File Knife too (much faster), but not sure if you ever embraced that tool (I think I mentioned it to you previously).

Sun 08/11/2019 13:28:28.45 C:\Temp>sfk list -juststat -since 90d -dir c:\temp *.*
24 files, 155 dirs, 131 kb, 131605 bytes.
skipped 19 hidden files, 0 hidden dirs.

Open in new window


»bp
Agree, I have Swiss File Knife, however I need to perform this from an external VM and I want to avoid it installing.
Thank you for your help.
@(
  ECHO OFF
  SETLOCAL EnableExtensions EnableDelayedExpansion
  SET "_FileCount="
  SET "_CountPath=c:\Temp"
  SET "_EmptyPath=c:\Empty"
  IF NOT EXIST "!_EmptyPath!" (
    MD "!_EmptyPath!"
  )
  SET  "_FileGlob=*.csv"
  SET "_MinAge=/MinAge:30"
  SET "_Recurse=/S"
  SET "_RoboCopyCMD=ROBOCOPY "!_CountPath!" "!_EmptyPath!" !_FileGlob! /L /NS /NC /NFL /NDL /NP /NJH !_Recurse! !_MinAge!"
)

FOR /F "Tokens=4" %%A IN ('%_RoboCopyCMD% ^| FIND /I "Files : "') DO (
  SET "_FileCount=%%A"
  ECHO.Files="%%A"
)

ECHO.Number of csv files: %_FileCount%
IF EXIST "!_EmptyPath!" (
  RD /S /Q  "!_EmptyPath!"
)
ENDLOCAL
PAUSE

Open in new window

I tested and I had a big issue. My Count_Path was removed hopefully I did a backup before.
I prefer forfiles option as we don't create/remove any folder.
Anyway thank you for your help.
@NVIT: possible to have:
1-Number of csv files in folder and subfolders (as is)
2-Number of csv files in folder (new)
3-Number of csv files in folder 30 or more days old (new)
4-Number of csv files in folder and subfolders 30 or more days old (as is)
Thank you for your help.
ASKER CERTIFIED SOLUTION
Avatar of NVIT
NVIT
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you. Unable to test it right now. I will keep you informed.
Thank you very much. It works!
Last question about this subject. If I want to set up dynamically /d to take into account the various files with a modified date after 01-08-2019 how should I proceed?
Why does it have to be BAT when Powershell is quick, powerful and comes with Windows so nothing new to install?

Quick search gives several examples that can be easily tweaked:
https://social.technet.microsoft.com/Forums/en-US/a3d8d3f8-f37f-4022-9e11-2bbfca833f1a/checking-a-directory-for-files-older-than-5-minutes?forum=winserverpowershell
> ... to set up dynamically /d ...
> ... to take into account the various files
> ... with a modified date after 01-08-2019

This request is unclear.

> ... to set up dynamically /d ...
Your original question states that /d refers to Date. Do you want the choice of different dates/days old, e.g. 1, 5, 10, 20, 30, 40, etc.?

> ... to take into account the various files
Do you want the choice of different filetype, instead of CSV?

> ... with a modified date after 01-08-2019
See first response in this post.
Thank NVIT.
The last request was related to /d +01/8/2019
Your proposal support this parameter so all is ok. Thank you again for your support.