I am trying to make an script that count all the files extension in an HDD or folder and save it into a csv file or text file.
I have several external HDDs with many files inside folders and subfolders.
I want to count how many files are by file extension.
I do not know the file extensions in the HDDs, in some could be mp4, doc, xls in others mkv, flac, jpg, txt and many more.
I found the next command that count all files extension recursively and save as txt file:
I tried my script something like this but doesn’t work:
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
set theDestinationList to (choose folder with prompt "Select where to save the CSV file and name:”)
tell application "Terminal"
find theSourceFolder -type f | sed -n 's/..*\.//p' | sort | uniq -c > theDestinationList/*.csv
end tell
Also, is there any way to exclude the hidden files?
and gives the the total count of all the files?
Thank you in advance for your kind help.
Model: mac mini 2011
AppleScript: 2.6.1
Browser: Safari 537.36
Operating System: macOS 10.9
Command-line tools are run in Applescripts with the do-shell-script command, and, FWIW, I’ve included a script below that does what you want. However, running this on an entire hard drive (especially if it’s a boot drive) may not work, and, for that, basic AppleScript probably is not a good solution.
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
set theSourceFolder to quoted form of POSIX path of theSourceFolder
set textFile to choose file name with prompt "Choose file name" default name "zCARPA"
set textFile to quoted form of (POSIX path of textFile & ".txt")
do shell script "find " & theSourceFolder & " -type f | sed -n " & quoted form of "s/..*\\.//p" & " | sort | uniq -c > " & textFile
BTW, I do not know how to modify the above command line to omit hidden files, and I’ll add something later to report the total number of files. Also, the Find command sees apps (and some other files) as folders, which may cause you to see some odd results.
The following will prompt for a file name–do not include the file extension. I don’t know any simple way to omit the hidden files but I will give that some thought.
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
set theSourceFolder to quoted form of POSIX path of theSourceFolder
set textFile to choose file name with prompt "Choose file name" default name "zCARPA"
set textFile to quoted form of (POSIX path of textFile & ".txt")
do shell script "find " & theSourceFolder & " -type f | sed -n " & quoted form of "s/..*\\.//p" & " | sort | uniq -c > " & textFile
This problem can be solved successfully with plain AppleScript using recursive search and System Events.
But this algorithm is time-consuming, therefore it is better to use AppleScriptObjC here, for maximum speed and reliability of the results. In addition, AppleScriptObjC has a simple method for filtering unnecessary content, such as hidden files.
I will try to publish a similar script, but now I need to go to work.
I incorporated the above command line in my script and it does appear to work. Getting the quoting correct was a real bear. Anyways, my script remains a kludge and KniazidisR’s AppleScriptObjC version will be the one to use.
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
set theSourceFolder to quoted form of POSIX path of theSourceFolder
set textFile to choose file name with prompt "Choose file name" default name "zCARPA"
set textFile to quoted form of (POSIX path of textFile & ".txt")
do shell script "find " & theSourceFolder & " \\( ! -regex " & quoted form of ".*/\\..*" & " \\) -type f | sed -n " & quoted form of "s/..*\\.//p" & " | sort | uniq -c > " & textFile
This is an AppleScriptObjC solution. It assumes every item with an extension is a file, which may include some folders, depending on how you name things. But it skips invisible items, as well as items within package files. And it sorts the list by count.
use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use scripting additions
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
-- get all files
set fileManager to current application's NSFileManager's defaultManager()
set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants) + (get current application's NSDirectoryEnumerationSkipsHiddenFiles)
set theFiles to (fileManager's enumeratorAtURL:theSourceFolder includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value))'s allObjects()
-- get just extensions
set theExtensions to theFiles's valueForKey:"pathExtension"
-- remove empty/missing extensions
set theFilter to current application's NSPredicate's predicateWithFormat:"SELF != ''"
set theExtensions to theExtensions's filteredArrayUsingPredicate:theFilter
-- make counted set, which does counting for us
set theSet to current application's NSCountedSet's setWithArray:theExtensions
-- build array of records so we can sort
set theResults to current application's NSMutableArray's array()
repeat with aValue in theSet's allObjects()
(theResults's addObject:{theCount:theSet's countForObject:aValue, theValue:((theSet's countForObject:aValue) as text) & "," & (aValue as text)})
end repeat
-- get total count
set theCount to theResults's valueForKeyPath:"@sum.theCount"
-- sort list by count
set sortDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"theCount" ascending:false
theResults's sortUsingDescriptors:{sortDesc}
-- create text and save
set theText to (((theResults's valueForKey:"theValue")'s componentsJoinedByString:linefeed) as text) & linefeed & (theCount as integer as text) & ",Total"
-- write file to desktop
set deskPath to path to desktop as text
set fileRef to (open for access ((deskPath & "Results.csv") as «class furl») with write permission)
set eof fileRef to 0
write theText to fileRef as «class utf8»
close access fileRef
This version only returns extensions and omits anything from paths containing “/.”:
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
set theSourceFolder to quoted form of POSIX path of theSourceFolder
set textFile to choose file name with prompt "Choose file name" default name "zCARPA.txt"
set textFile to quoted form of (POSIX path of textFile)
do shell script "find " & theSourceFolder & " -type f | sed -En " & quoted form of "/.*\\/\\..*/ !s|.+\\.([^./]+$)|\\1|p" & " | sort | uniq -c > " & textFile
I had another look, and it appears the part-paths were appearing only for items in packages. That might be coincidence, but they’re also files without extensions.
There is, but it’s a bit tricky. You need to save it as a script library in ~/Library/Script Libraries, and call it from there. You would also have to convert theSourceFolder to an NSURL. So the code would be like:
use AppleScript version "2.3" -- macOS 10.9
use framework "Foundation"
use scripting additions
on reportOnFolder(theSourceFolder)
set theSourceFolder to current application's |NSURL|'s fileURLWithPath:(POSIX path of theSourceFolder)
-- get all files
set fileManager to current application's NSFileManager's defaultManager()
[...as above in here]
close access fileRef
end reportOnFolder
You would need to save it as a .scptd bundle, and edit the bundle’s Info.plist file to include:
<key>OSAAppleScriptObjCEnabled</key>
<true/>
Then your main script would call it something like:
use AppleScript version "2.3"
use scripting additions
use theLib: script "Name of your lib file" -- change to suit
set theSourceFolder to (choose folder with prompt "Select an HDD or folder:")
tell theLib to reportOnFolder(theSourceFolder)
Nigel. Your version works great. Just as a test, I ran the script on a huge folder on an external drive, and it’s surprising how fast it is (under a second).