i have a script where i’m currently using the command
tell application "Finder" to set folder_list to every item of entire contents of folder myFolder
which runs reasonably slow especially the longer the list is to return. The reason I use it is because it returns not only the contents of the folder but all of its subfolders as well.
I’ve been trying to use a version of the command with System Events because it runs so much faster, but I can’t figure out how to get it to return results from subfolders of the target folder
tell application "System Events" to set folder_list to the path of every disk item of folder myFolder
that is what i have so far. can anyone point me in the right direction to get results for subfolders?
As you’ve found, the Finder is hopelessly slow. System Events doesn’t have an equivalent to entire contents, so you need to get all the items and recursively search each folder. It’s fairly tedious.
An alternative is to use AppleScriptObjC. It has the advantage of being much faster, although pre-10.11 you’ll get back a list of POSIX paths rather than files. So:
use scripting additions
use framework "Foundation"
on getItemsIn:posixPathOfFolder
-- make URL
set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
-- make file manager
set theFileManager to current application's NSFileManager's new()
-- get all except hidden items and items within packages
set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
-- convert URLs to POSIX paths and coerce to list
return (allURLs's valueForKey:"path") as list
end getItemsIn:
set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder
Thanks! that works great. I had also been tinkering with doing it with a shell script but that was returning all the paths as a big paragraph block that I then had to work with to get formatted nicely. That was a bit of a pain, this is much cleaner. Thanks again.
Shane will certainly offer a more global answer but here is a script returning every .png and .jpeg / .jpg files.
Alas, the filter is case sensitive.
use scripting additions
use framework "Foundation"
on getItemsIn:posixPathOfFolder
-- make URL
set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
-- make file manager
set theFileManager to current application's NSFileManager's new()
-- get all except hidden items and items within packages
set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
-- convert URLs to POSIX paths and coerce to list
--return (allURLs's valueForKey:"path") as list # Original instruction
set theArray to (allURLs's valueForKey:"path")
set thePred to current application's NSPredicate's predicateWithFormat:"(self ENDSWITH '.jpg') OR (self ENDSWITH '.jpeg') OR (self ENDSWith '.png')"
return (theArray's filteredArrayUsingPredicate:thePred) as list
end getItemsIn:
set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder
It’s worth reading up on predicates. As well as ENDSWITH, as Yvan used, there’s BEGINSWITH, CONTAINS, LIKE and MATCHES. They’re generally written in caps by convention, although they don’t have to be. For like, * and ? can be used as wildcards; match takes a regular expression pattern.
To ignore case, you insert “[c]”, as in “BEGINSWITH[c]”. Similarly, [cd] will ignore case and diacriticals.
Two other options are UTI-CONFORMS-TO and UTI-EQUALS.
As well as using self, which here means the full path, you can use lastPathComponent, which is the name, pathExtension for the extension, stringByDeletingLastPathComponent for the path to the parent folder, and stringByDeletingPathExtension.
Thanks Shane. I’m sure they are.
I’m trying to learn about 15 things right now, so this will have to wait.
I have a shell script solution – that will have to do for now.
I searched your book, but didn’t find much. Did I miss something?
Hello Shane.
As I missed the use of [c] in your script 17-1 (with a fever at 39°C), now that it’s 38°C I rwrote the instruction defining thepred as:
set thePred to current application’s NSPredicate’s predicateWithFormat:“(pathExtension like[c] ‘jpg’) OR (pathExtension like[c] ‘jpeg’) OR (pathExtension like[c] ‘png’)”
But maybe I missed also an other feature :
Is it posible to use type identifiers in a filter ?
use scripting additions
use framework "Foundation"
on getItemsIn:posixPathOfFolder searchedExtensions:theList
-- make URL
set theNSURL to current application's class "NSURL"'s fileURLWithPath:posixPathOfFolder
-- make file manager
set theFileManager to current application's NSFileManager's new()
-- get all except hidden items and items within packages
set allURLs to (theFileManager's enumeratorAtURL:theNSURL includingPropertiesForKeys:{"path"} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
set thePred to current application's NSPredicate's predicateWithFormat:"pathExtension IN[c] %@" argumentArray:{theList}
set theURLs to allURLs's filteredArrayUsingPredicate:thePred
-- convert URLs to POSIX paths
return (theURLs's valueForKey:"path") as list
end getItemsIn:searchedExtensions:
set posixPathOfFolder to POSIX path of (choose folder)
set listOfPaths to my getItemsIn:posixPathOfFolder searchedExtensions:{"jpg", "jpeg", "png"}
I’m wondering if it’s really a good idea to keep only the paths when building allURLs.
It eat cycles but I guess that the created objet becoming smaller, filtering it will be faster.
Really, the only way to answer questions like that is to make your own timings. My guess is it doesn’t make a lot of difference.
The other issue is what kind of result you want. If you’re on 10.11, you can skip changing to paths and when you coerce the URLs to a list they will become files (class furl»). Depending on what you’re doing, that might be more useful.