4

What I'm trying to do is make a batch file that'll recursively go into every folder and count the number of files in each folder. However, I've spent the last hour trying various things and it isn't working.

I want the output to look like: X:Y where X is the folder name and Y is the # of files in X.

setlocal EnableDelayedExpansion
set current=blank
FOR /D %%G in ("*") DO set current=%%G && call:count

:count
set count=0
for %%A in (*) do set /a count+=1
echo !current!:!count!>>"D:\User\Some\Directory\count.txt"

But this doesn't work. The output is giving the same number for each folder. The number it's outputting is the number of files in the directory itself, which I think is the problem.

Specifically, if I'm in C:\User\Example and it has three folders, A, B, and C, I want the number of files in C:\User\Example\A and so on, but it's giving me the number of files in C:\User\Example. Hope that makes sense.

Note: In my use case, the folders will not contain sub-directories.

Ambushes
  • 53
  • 1
  • 1
  • 9
  • Have you considered PowerShell?? You could learn the basics of it *AND* write the needed script in less time it would take to trick MSDOS into doing it. – James Curran Aug 04 '16 at 19:37
  • You never do a change directory with the current folder variable. I normally just use PUSHD and POPD though. – Squashman Aug 04 '16 at 19:44
  • @Squashman this is what I thought was the issue... I thought FOR /D would go through all the folders, but it doesn't look like it does. Any idea what I could in a FOR loop? – Ambushes Aug 04 '16 at 19:47
  • @James Curran never tried using Powershell. Are there any special commands in Powershell that would make this easier? – Ambushes Aug 04 '16 at 19:47
  • @Ambushes, the `FOR /D` is just giving you a listing of directories. It does not traverse into them. – Squashman Aug 04 '16 at 19:48
  • How should the output look like if for instance folder `A` contains 3 files and a sub-directory which contains 2 files? Should the output be: a) `A: 5`, or b) `A: 3`, or c) `A: 3` & `A\D: 2`? Please clarify by [editing](http://stackoverflow.com/posts/38775955/edit) your question... – aschipfl Aug 04 '16 at 20:04
  • @aschipfl Nothing that complicated. Each folder will not contain any sub-directories in my use case. – Ambushes Aug 04 '16 at 20:08

4 Answers4

4

A little different approach.

 @echo off

 FOR /D %%G in ("*") DO (
     PUSHD "%%G"
     FOR /F "delims=" %%H in ('dir /a-d /b * ^|find /C /V ""') DO echo %%G %%H>>"..\count.txt"
     POPD
 )
Squashman
  • 13,649
  • 5
  • 27
  • 36
  • This did the trick. I'll google to find out what PUSHD and POPD are doing (I understand what "pushing" and "popping" is since I know C but I'll have to understand how they're being used here.) Thanks a lot. – Ambushes Aug 04 '16 at 20:06
  • 3
    You could put parentheses around the entire `for` loop and do a single `>` redirection to improve performance and not having to care whether the text file already exists... – aschipfl Aug 04 '16 at 20:12
  • 1
    @Ambushes, you could easily just do a `CD %%G` and `CD ..` instead of `PUSHD` and `POPD`. – Squashman Aug 04 '16 at 20:13
2

this works:

note that you have to collate set current=%%G&& call:count or current value is "A " (trailing space, not that you want) And when you scan the subdir, you have to prefix * by your current dir

@echo off
del count.txt

setlocal EnableDelayedExpansion
set current=blank


FOR /D %%G in ("*") DO set current=%%G&& call:count

goto end

:count
set count=0
for %%A in (!current!\*) do set /a count+=1
echo !current!:!count!>>"count.txt"

:end
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Ah i see. Your code looks like it would work, but when I tried it the counts were still inaccurate. In my use case, the number of files would only ever be 1 or 4, but your results have 3 as the count in the majority of cases. – Ambushes Aug 04 '16 at 19:58
  • You may eliminate `current` and pass its value via a parameter: `(FOR /D %%G in ("*") DO call :count "%%G") > count.txt` and in the subroutine: `for %%A in (%%~1\*) do set /a count+=1` and then `echo %%~1:%count%`. This mod also eliminate the `del count.txt`, the first `set current=blank` and the need for Delayed Expansion, so the final version would have just 8 lines. – Aacini Aug 05 '16 at 13:13
2

The answers to this question looks like a collection of different ways to do the same thing! Here it is another one:

@echo off
setlocal EnableDelayedExpansion

for /F "tokens=1,2 delims=\" %%a in ('findstr /M /S "^" *.*') do (
   if "%%b" neq "" (
      set "name=%%a"
      set /A "count[!name: =_!]+=1"
   )
)
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do (
   set "name=%%a"
   echo !name:_= !:%%b
)) > count.txt

This method look complicated because the management of spaces in the folders names. If folders don't have spaces, 6 lines (and Delayed Expansion) could be removed; that is:

@echo off
setlocal

for /F "tokens=1,2 delims=\" %%a in ('findstr /M /S "^" *.*') do (
   if "%%b" neq "" set /A "count[%%a]+=1"
)
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a:%%b) > count.txt
Aacini
  • 65,180
  • 12
  • 72
  • 108
1

Here is a PowerShell script to handle it:

Get-ChildItem -Path . -Recurse -ErrorAction SilentlyContinue -Force 
   | Where-Object { $_.Attributes -eq "Directory"} 
   | ForEach-Object {Write-Host $_.Name, $_.GetFiles().Count }

The prints to the screen, but writing to a file is simple.

The scans all the way down. If you just want the first layer of folders, remove the "-Recurse"

The advantage is that you are doing real actions on real objects, instead of trying to trick the OS into doing things it's not really intended for, by parsing text.

Here, it should be relatively simple to figure out what this is doing, even if you have little knowledge of PowerShell (Get a list of children, from this path, which are directories, and for each of them, print it's name, and the count of files in it.)

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • Very interesting! I thought PowerShell and MS-DOS were similar, but clearly not haha. Would you recommend someone to pickup PowerShell? I'm only trying to make basic MS-DOS scripts to make my life easier at work, since my job involves a lot of repetitive actions that can be scripted. I'm still a newbie programmer (Only know C, Python, a little bit of Java and Ruby), would Powershell be something worth learning? – Ambushes Aug 04 '16 at 20:11
  • PowerShell was invented specifically to address the shortcomings of MSDOS batch files. Picking it up is fairly easy. I'm just basically aware of it's existence, but I just googled "powershell recursive file search" and got most of that script. It would help to know .NET (for instance, the Get-ChildItem command here is returning a list of .NET DirectoryInfo objects.) – James Curran Aug 04 '16 at 21:06
  • Let's be very clear about this matter: PowerShell is _more powerful_ than Batch files; there are many advanced and complex processes that can be done in a much simpler way in PowerShell than in Batch. This does NOT means that PowerShell is "simpler" than Batch. It is not. There are _a lot_ of concepts that you must know in order to successfully use PowerShell or you may run into problems that don't even exist in a Batch file. Also, when just a basic script is required, the PowerShell solution usually run _much slower_ than the equivalent Batch file. – Aacini Aug 05 '16 at 06:13
  • 1
    See [this](http://stackoverflow.com/questions/35313953/findstr-always-fails-to-find-hash-string-in-text-file/35324145#35324145) or [this](http://stackoverflow.com/questions/38000901/loop-through-ascii-codes-in-batch-file/38006019#38006019) or [this](http://stackoverflow.com/questions/35637893/replace-multiple-lines-in-powershell), etc. Finally, read [this article](https://helgeklein.com/blog/2014/11/hate-powershell/) and _the user's comments_ at end of [this one](http://windowsitpro.com/powershell/break-your-batch-habit-and-move-powershell). – Aacini Aug 05 '16 at 06:14