40

Within a directory, and recursively within it's sub-directories, meaning every directory within a directory is processed, how do I compile a complete list of unique extensions within the directory?

OS is Windows XP with all the current updates, but I okay running script if I'm able to tell what it's doing, though I would prefer not to have to install dot-net, since I really do not like it.

6 Answers 6

40

This batch script will do it.

@echo off

set target=%~1
if "%target%"=="" set target=%cd%

setlocal EnableDelayedExpansion

set LF=^


rem Previous two lines deliberately left blank for LF to work.

for /f "tokens=*" %%i in ('dir /b /s /a:-d "%target%"') do (
    set ext=%%~xi
    if "!ext!"=="" set ext=FileWithNoExtension
    echo !extlist! | find "!ext!:" > nul
    if not !ERRORLEVEL! == 0 set extlist=!extlist!!ext!:
)

echo %extlist::=!LF!%

endlocal

Save it as any .bat file, and run it with the command batchfile (substitute whatever you named it) to list the current directory, or specify a path with batchfile "path". It will search all subdirectories.

If you want to export to a file, use batchfile >filename.txt (or batchfile "path" >filename.txt).

Explanation

Everything before the for /f... line just sets things up: it gets the target directory to search, enables delayed expansion which lets me do update variables in the loop and defines a newline (LF) that I can use for neater output. Oh, and the %~1 means "get the first argument, removing quotes" which prevents doubled-up quotes - see for /?.

The loop uses that dir /b /s /a:-d "%target%" command, grabbing a list of all files in all subdirectories under the target.

%%~xi extracts the extension out of the full paths the dir command returns.

An empty extension is replaced with "FileWithNoExtension", so you know there is such a file - if I added an empty line instead, it's not quite as obvious.

The whole current list if sent through a find command, to ensure uniqueness. The text output of the find command is sent to nul, essentially a black hole - we don't want it. Since we always append a : at the end of the list, we should also make sure the search query ends with a : so it doesn't match partial results - see comments.

%ERRORLEVEL% is set by the find command, a value of 0 indicates there was a match. So if it's not 0, the current extension is not on the list so far and should be added.

The echo line basically outputs, and I also replace my placeholders (:) with newlines to make it look nice.

4
  • +1 @Bob: Amazing answer, adding the explanation was a huge help too. Just tested the script, reviewed the results of the test, and everything worked great. Again, thanks!
    – blunders
    Mar 7, 2012 at 17:04
  • 1
    It worked PERFECTLY! I used the following syntax: batchfile "path" >filename.txt Oct 28, 2014 at 20:41
  • Great script! But there is a small bug with it : if the folder contain files aaa.css and zzz.cs, extension .cs will not be reported by the script.
    – Goozak
    Oct 20, 2016 at 17:24
  • 1
    @Goozak Whoops. Fixed now. The wonders of text searching... had to make sure the search query ended with : to force it to match boundaries.
    – Bob
    Oct 20, 2016 at 23:08
38

Although not strictly meeting the requirement for a batch script, I have used a single-line piped PowerShell script:

Get-Childitem C:\MyDirectory -Recurse -File | Group Extension -NoElement | Sort Count -Desc > FileExtensions.txt

Where:

  1. Get-ChildItem C:\MyDirectory -Recurse retrieves all files in the directory and subdirectories.
  2. Group Extension -NoElement groups the results by the file extension.
  3. Sort Count -Desc Sorts the results by the number of matching extensions in each group (from most to least).
  4. > FileExtensions.txt pipes the results to the specified file.

You could potentially run it from the command line/batch file:

Powershell -Command "& Get-Childitem C:\MyDirectory -Recurse -File | Group Extension -NoElement | Sort Count -Desc > FileExtensions.txt"

If you remove C:\MyDirectory it will execute in the current directory.

Edit 2021-04-20: As per the comment from @ManSamVampire, if you want to find hidden files as well, you should add -Force before -Recurse in the above command.

At the end it will produce a FileExtensions.txt containing something like the following:

+-------+------+
| Count | Name |
+-------+------+
| ----- | ---- |
| 8216  | .xml |
| 4854  | .png |
| 4378  | .dll |
| 3565  | .htm |
| ...   | ...  |
+-------+------+

Depending on your folder structure, you may occasionally get errors notifying you that you have a long path.

Get-ChildItem : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

Any subdirectories in there will also not be parsed but the results for everything else will still show.

Notes

You will of course need PowerShell which you can grab from here. It can also run on multiple operating systems.

3
  • Thanks, agree that it's a useful answer. On an unrelated note, bit puzzled how you've posted only single answer, yet have the "Fanatic" badge for visiting Superuser for 100 consecutive days. Do you have the site bookmarked or something?
    – blunders
    Sep 18, 2014 at 4:02
  • The badge was awarded in 2010 when I effectively lurked, but I'm far more active on SO: stackoverflow.com/users/31532/dan-atkinson. :) Sep 18, 2014 at 12:05
  • 1
    This is great. Though, I also had to add the -Force parameter to the Get-ChildItem command, to include hidden files as well. Mar 27, 2021 at 15:23
4

To list all unique extensions from cmd under the path your on use:

Powershell -Command "Get-ChildItem . -Include *.* -Recurse | Select-Object Extension | Sort-Object -Property Extension -Unique"
4

Here's a detailed answer using PowerShell (with Windows XP you'll have to install PowerShell):

Hey, Scripting Guy! How Can I Use Windows PowerShell to Pick Out the Unique File Extensions Used in a Collection of Files?

5
  • 1
    While PowerShell is definitely much easier than the command line, it is based on .NET. Which, unfortunately, goes against "I would prefer not to have to install dot-net".
    – Bob
    Mar 7, 2012 at 15:36
  • 1
    +1 @RichardM: Agree with Bob. Also, the code related to the counting of extension instances found -- not knowing anything about PowerShell -- appears very memory heavy; meaning instead of just keeping a count of every instance, it's I believe creating an array to store duplicate instances of an extension for each extension, then doing a count for each extension array at the end, which to me seems like a very odd way of counting extension instances. Am I missing something? (That said, the first PowerShell one-liner is nice, and I'd try it if I didn't dislike dotnet.)
    – blunders
    Mar 7, 2012 at 22:05
  • 1
    That's fair. This question may draw searchers who are more open to a PowerShell solution. Mind you, a decent Google search will find the above link as well.
    – RichardM
    Mar 9, 2012 at 13:48
  • 3
    +1 for this link. blunders obvious dislikes everything .net, but that doesn't mean that the solution above is the best long term solution to this problem. The more languages the better i think. Jun 16, 2012 at 4:12
  • 1
    Here's another link that addresses recursive search, using powershell. robertbigec.wordpress.com/2011/01/07/…
    – goodeye
    Jan 4, 2013 at 3:09
0

I found it useful to change

if "!ext!"=="" set ext=FileWithNoExtension

to

if "!ext!"=="" set ext=.FileWithNoExtension

and to change

echo %extlist::=!LF!%

to

echo %extlist::=!LF!% > ext-list.txt

The generated file contained (no linefeeds, but no matter) .bat.pdf.skp.ai.png.jpg.tif.pcp.txt.lst.ttf.dfont.psd.indd.docx.PDF.JPG.gif.jpeg.dwg.exr.FileWithNoExtension.vrlmap.sat.bak.ctb

which I was then able to use for my project.

0

I use git bash an just run this one liner

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .