Replace Slow Finder First Folder Code with Faster Shell Script?

I have a series of subfolders with a parent folder called “Inventory” within a internal hard drive.

Each subfolder name consists of a number, a hyphen and some text, such as:

“329 - Antique Photo Album”.

The following script, compiled as a app, displays a dialog box into which a number is typed.

If one of the subfolders matches the user inputed number the script opens that subfolder in a new Finder window.

The script then opens each of that folder’s sub subfolders, named “_R”, “GS”, “K”, “O”, “T”, “WA”, “WM” in new tabs in the Finder window just opened.

This takes up to 32 seconds.

The bottleneck is the line that finds the first folder so is there any way to use a shell script to find the folder instead, which should be faster.

All the shell scripts I have tried have failed so far have failed.

I am using High Sierra 10.13.6.

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")

set replaceText to text returned of theReply2

set theSubs to {"_R", "GS", "K", "O", "T", "WA", "WM"}

try
    
    set thePath to "Volumes:DA2.0:Inventory:" as alias
    
    tell application "Finder" to set theSubFolder to (first folder of thePath whose name starts with replaceText & " - ")
    
    tell application "Finder" to open theSubFolder
    
    repeat with x from 1 to count of items in theSubs
        
        
        tell application "Finder" to set theSubSubFolder to (first folder of theSubFolder whose name is item x of theSubs)
        
        tell application "System Events"
            tell application process "Finder" to set frontmost to true
            keystroke "t" using command down
        end tell
        
        tell application "Finder" to set target of front window to theSubSubFolder as alias
        
    end repeat
    
end try

tabbyapple. The following script worked on my Sequoia computer. It takes a slightly different approach in that it opens the folders then merges them in one Finder window with tabs. It takes a second or so to run. The script needs refinement and is on a proof-of-concept basis.

set folderOne to "Macintosh HD:Users:robert:Inventory:" as alias --set to desired value
set theSubs to {"_R", "GS", "K", "O", "T", "WA", "WM"}

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

tell application "Finder"
	try
		set folderTwo to first folder in folder folderOne whose name begins with replaceText & " - "
		set theSubfolders to every folder of folderTwo
	on error
		display dialog "A folder that begins with that replacement text was not found." buttons {"OK"} cancel button 1 default button 1
	end try
	repeat with aFolder in theSubfolders
		if name of aFolder is in theSubs then open aFolder
	end repeat
	open folderTwo
end tell

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Merge All Windows" of menu "Window" of menu bar 1
end tell

This is a script that works as envisioned by tabbyapple’s script. This script is slower than my earlier script because a delay is required every time the newTab handler is run. I’ve set the delay to 0.5, but a value of 0.1 worked on my M2 Mac mini.

set folderOne to "Macintosh HD:Users:robert:Inventory:" as alias --set to desired path
set theSubs to {"_R", "GS", "K", "O", "T", "WA", "WM"}
set newTabDelay to 0.5 --test smaller values

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

tell application "Finder"
	try
		set folderTwo to first folder in folder folderOne whose name begins with replaceText & " - "
		set theSubfolders to every folder of folderTwo
		my newTab(newTabDelay)
		set target of Finder window 1 to folderTwo
	on error
		display dialog "A folder that begins with that replacement text was not found." buttons {"OK"} cancel button 1 default button 1
	end try
	
	repeat with aFolder in theSubfolders
		if name of aFolder is in theSubs then
			my newTab(newTabDelay)
			set target of Finder window 1 to aFolder
		end if
	end repeat
end tell

on newTab(theDelay)
	tell application "System Events" to tell process "Finder"
		set frontmost to true
		keystroke "t" using command down
	end tell
	delay theDelay
end newTab

BTW, the above script stops with the focus on the last tab in the Finder window. I don’t know of a way to move the focus to tab 1 (if that’s desired) but this can be done with GUI scripting. The following would be added just above the newTab handler.

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Show Next Tab" of menu "Window" of menu bar 1
end tell

Using “Whose” clauses in Finder is very slow.
It is much faster to get all the folders first and then sort them out yourself.

BTW, how many folders are in the Inventory folder?

Just over 300 so far.

I cross posted this on Stack OverFlow and was able to modify several lines of code provided by a user there to the following, which works in 6-7 seconds.


set returnDialog to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set returnedText to text returned of returnDialog

set containFolder to "Volumes:DA2.0:Inventory:" as alias

tell application "System Events"
	set specf to (first folder of containFolder whose name begins with (returnedText & " - "))
	open specf
	
	set specf to path of specf as alias
	set subf to folders of specf
	
end tell

tell application "Finder" to activate
repeat with eaf in subf
	tell application "System Events"
		keystroke "t" using command down
		set mypath to path of eaf
		tell application "Finder" to set target of front window to mypath
	end tell
end repeat

Try my version of your first script and see how fast it is.

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")

set replaceText to text returned of theReply2

set theSubs to {"_R", "GS", "K", "O", "T", "WA", "WM"}

set thePath to "DA2.0:Inventory:"
set theSubFolder to FindFolder(thePath, replaceText & " - ")
if class of theSubFolder = boolean then return
try
	tell application "Finder" to open theSubFolder
on error
	return
end try
repeat with x from 1 to count theSubs
	try
		tell application "Finder" to set theSubSubFolder to folder (item x of theSubs) of theSubFolder
		
		tell application "System Events"
			tell application process "Finder" to set frontmost to true
			keystroke "t" using command down
		end tell
		
		tell application "Finder" to set target of front window to theSubSubFolder
	end try
end repeat

on FindFolder(aFolder, startText)
	local allFolders, folderNames, i
	tell application "Finder"
		tell folders of folder aFolder to set {allFolders, folderNames} to {it, name}
	end tell
	repeat with i from 1 to count folderNames
		if (item i of folderNames) starts with startText then return item i of allFolders
	end repeat
	return false
end FindFolder

** EDIT ** - I did a few minor edits, try speed test again
I edited it a few more times to streamline it

No CMD-t version.

This setting:
System Settings > Desktop & Dock > Prefer tabs when opening documents > ALWAYS
will allow the finder settings in the code below to work as intended. Subfolder windows open in TABS as desired.

This code does not address the delays in finding the first ( selected through the input dialog ) folder. If there are thousands of folders in that folder I would use an ASObjC handler for finding the folder rather than asking the finder for it.

Building paths to the sub-folders should be more efficient than asking the finder for them as well, but unless there are large numbers of files or sub-sub-folders in the sub-folders then this improvement will be minor.

tell application "Finder"
	activate
	set {foldersOpenInNewTabs, foldersOpenInNewWindows} to my storeFinderSettings()
	
	set theInventoryPath to "Macintosh HD:Users:username:Desktop:Inventory:" as alias
	set replaceText to text returned of (display dialog "Enter folder identifier string" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
	set theSubFolder to (first folder of theInventoryPath whose name starts with replaceText & " - ")
	open theSubFolder
	set theSubFolder to (theSubFolder as text)
	
	set theSubSubFolders to {"_R", "GS", "K", "O", "T", "WA", "WM"}
	repeat with indx from 1 to count of items in theSubSubFolders
		open theSubFolder & item indx of theSubSubFolders & ":"
	end repeat
	
	my restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
end tell


on storeFinderSettings()
	tell application "Finder"
		set foldersOpenInNewTabs to folders open in new tabs of Finder preferences
		set foldersOpenInNewWindows to folders open in new windows of Finder preferences
		set folders open in new tabs of Finder preferences to true
		set folders open in new windows of Finder preferences to false
		return {foldersOpenInNewTabs, foldersOpenInNewWindows}
	end tell
end storeFinderSettings
on restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
	tell application "Finder"
		set folders open in new tabs of Finder preferences to foldersOpenInNewTabs
		set folders open in new windows of Finder preferences to foldersOpenInNewWindows
	end tell
end restoreFinderSettings

Paul, my version is still pretty speedy finding folders with the Finder, because I removed the WHERE clause

Robert,

I don’t doubt that a repeat loop is faster than a finder whose clause. I’m not convinced either is significant with only 300 possible sub-folders, but I haven’t generated a couple hundred test folders to verify.

Ok, now I have generated a few or three hundred sub-folders to verify, and it is slow. Color me non-plussed. Here’s a full-on quick-folder-finding version that meets the OP ask. No longer terse, but that’s what libraries are for. This version takes 3.1 seconds to complete with a test sub-folder containing 310 folders.

use scripting additions
use framework "Foundation"

tell application "Finder"
	activate
	set theInventoryPath to "Macintosh HD:Users:username:Desktop:Inventory:" as alias
	set findText to text returned of (display dialog "Enter folder identifier string" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
	set theSubFolder to my NSURL_Filename_Contains(my FileSystem_List_Folders(theInventoryPath), findText)
	open (theSubFolder as alias)
	set {foldersOpenInNewTabs, foldersOpenInNewWindows} to my storeFinderSettings()
	set theSubFolder to (theSubFolder as text)
	set theSubSubFolders to {"_R", "GS", "K", "O", "T", "WA", "WM"}
	repeat with indx from 1 to count of items in theSubSubFolders
		open theSubFolder & item indx of theSubSubFolders & ":"
	end repeat
	my restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
end tell

on storeFinderSettings()
	tell application "Finder"
		set foldersOpenInNewTabs to folders open in new tabs of Finder preferences
		set foldersOpenInNewWindows to folders open in new windows of Finder preferences
		set folders open in new tabs of Finder preferences to true
		set folders open in new windows of Finder preferences to false
		return {foldersOpenInNewTabs, foldersOpenInNewWindows}
	end tell
end storeFinderSettings
on restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
	tell application "Finder"
		set folders open in new tabs of Finder preferences to foldersOpenInNewTabs
		set folders open in new windows of Finder preferences to foldersOpenInNewWindows
	end tell
end restoreFinderSettings
on NSURL_Filename_Contains(NSURLArray, matchString)
	set thePredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent CONTAINS %@", matchString)
	return NSURLArray's filteredArrayUsingPredicate:thePredicate
end NSURL_Filename_Contains
on FileSystem_List_Folders(folderObject)
	try
		theFolders of FileSystem_List_Folders_Files_Packages(folderObject)
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_List_Folders>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_List_Folders
on FileSystem_List_Folders_Files_Packages(folderObject)
	try
		set sourceFolderNSURL to FileSystem_Convert_Object_To_NSURL(folderObject)
		set theEntireContents to FileSystem_List_Contents(sourceFolderNSURL)
		set directoryKey to current application's NSURLIsDirectoryKey
		set packageKey to current application's NSURLIsPackageKey
		set theFolders to current application's NSMutableArray's new()
		set theFiles to current application's NSMutableArray's new()
		set thePackages to current application's NSMutableArray's new()
		set booleanTrue to current application's NSNumber's numberWithBool:true
		repeat with thisObject in theEntireContents
			set {theResult, IsADirectory} to (thisObject's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
			if IsADirectory is booleanTrue then
				set {theResult, IsAPackage} to (thisObject's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
				if not (IsAPackage is booleanTrue) then
					(theFolders's addObject:thisObject)
				else
					(thePackages's addObject:thisObject)
				end if
			else
				(theFiles's addObject:thisObject)
			end if
		end repeat
		theFiles's removeObjectsInArray:theFolders
		return {theEntireContents:theEntireContents, theFolders:theFolders, theFiles:theFiles, thePackages:thePackages}
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_List_Folders_Files_Packages>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_List_Folders_Files_Packages
on FileSystem_List_Contents(folderObject)
	try
		set folderObject to FileSystem_Convert_Object_To_NSURL(folderObject)
		set theEntireContents to ((current application's NSFileManager's defaultManager's enumeratorAtURL:folderObject includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects())'s mutableCopy()
		return theEntireContents
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_List_Contents>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_List_Contents
on FileSystem_Convert_Object_To_NSURL(fileSystemObject)
	try
		set fileSystemObject to FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
		set fileSystemObject to current application's class "NSURL"'s fileURLWithPath:fileSystemObject
		return fileSystemObject
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Convert_Object_To_NSURL>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Convert_Object_To_NSURL
on FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
	try
		try
			set posixPath to POSIX path of fileSystemObject
		on error
			try
				tell application "System Events"
					set posixPath to POSIX path of ((path of disk item (fileSystemObject as string)) as alias)
				end tell
			on error
				set posixPath to POSIX path of (fileSystemObject as alias)
			end try
		end try
		return current application's NSString's stringWithString:posixPath
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Convert_Object_To_PosixPath>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Convert_Object_To_PosixPath

Robert. I tested your script but it simply stopped. It worked after I modified the handler as shown below. Perhaps I still don’t understand the OP’s requirements.

on FindFolder(aFolder, startText)
	local allFolders, folderNames, i
	tell application "Finder"
		tell folders of folder aFolder to set {allFolders, folderNames} to {it, name}
	end tell
	repeat with i from 1 to count folderNames
		if (item i of folderNames) begins with startText then return item i of allFolders
	end repeat
	return false
end FindFolder

I apparently misunderstood the OP’s requirement, and I’ve edited my script accordingly. I then ran a timing test with Script Geek. My test folder contained 300 folders and the target subfolder contained 7 subfolders. The timing result was 1.3 second.

set folderOne to "Store:Inventory:" as alias --set to desired value

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

tell application "Finder"
	try
		set folderTwo to first folder in folder folderOne whose name begins with replaceText & " - "
		set theSubfolders to every folder of folderTwo
	on error
		display dialog "A folder that begins with that replacement text was not found." buttons {"OK"} cancel button 1 default button 1
	end try
	open theSubfolders
	open folderTwo
end tell

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Merge All Windows" of menu "Window" of menu bar 1
end tell

Just for practice, I wrote an ASObjC script. The timing result was 1.5 second, so no reason to use this unless the number of subfolders increases substantially. This script may not work on older versions of macOS.

use framework "AppKit"
use framework "Foundation"
use scripting additions

set folderOne to "/Volumes/Store/Inventory" --set to desired value
set folderOne to current application's |NSURL|'s fileURLWithPath:folderOne

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

set folderOneContents to getFolders(folderOne)
set thePredicate to current application's class "NSPredicate"'s predicateWithFormat_("(lastPathComponent BEGINSWITH %@)", replaceText)
set folderTwo to (folderOneContents's filteredArrayUsingPredicate:thePredicate)'s objectAtIndex:0
set folderTwoContents to getFolders(folderTwo)'s valueForKey:"path"
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
repeat with aFolder in folderTwoContents
	(theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:aFolder)
end repeat
(theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:(folderTwo's |path|()))

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Merge All Windows" of menu "Window" of menu bar 1
end tell

on getFolders(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set folderKey to current application's NSURLIsDirectoryKey
	set packageKey to current application's NSURLIsPackageKey
	set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value)
	set theFolders to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aFolder} to (anItem's getResourceValue:(reference) forKey:folderKey |error|:(missing value))
		if aFolder as boolean is true then
			set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
			if aPackage as boolean is false then (theFolders's addObject:anItem)
		end if
	end repeat
	return theFolders
end getFolders
set folderOne to "volumes:DA2.0:Inventory2:" as alias --set to desired value

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

tell application "Finder"
	try
		set folderTwo to first folder in folder folderOne whose name begins with replaceText & " - "
		set theSubfolders to every folder of folderTwo
	on error
		display dialog "A folder that begins with that replacement text was not found." buttons {"OK"} cancel button 1 default button 1
	end try
	open theSubfolders
	open folderTwo
end tell

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Merge All Windows" of menu "Window" of menu bar 1
end tell

For testing purposes I created a second folder on the same drive “volumes:DA2.0:Inventory2:”.

This contains 1000 folders. Each folder contains the same seven empty subfolders. These folders are name “1 - Description” to “1000 - Description”.

I am using High Sierra 10.13.6 on a Mac Pro (Mid 2010) 2.8GHz Quad-Core Intel Xeon with four internal hard drives and 48GB of RAM.

The “Open folders in tabs instead of windows” preference is enabled and is found under Finder Preferences on this OS.

The tests are being performed while I have other applications running such as PhotoShop, Illustrator, multiple browsers, OpenOffice and some utility apps like Name Changer and PhotoMill.

Compiled as App:

When I tried this code for folder “10 - Description” this took 5 seconds; however, it also merged another open window with a single tab at the end (even if other open window is placed in dock)

Folder “549 - Description” a spinning beach ball was displayed for 106 seconds before the process was completed. Same unwanted merging of another open window.

Script Editor:

Folder “10 - Description” took 7 seconds. Same unwanted merging of another open window.

Folder “549 - Description” the created a “AppleEvent timed out” error. and the process dis not complete.

use framework "AppKit"
use framework "Foundation"
use scripting additions

set folderOne to "/Volumes/DA2.0/Inventory2" --set to desired value
set folderOne to current application's |NSURL|'s fileURLWithPath:folderOne

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2

set folderOneContents to getFolders(folderOne)
set thePredicate to current application's class "NSPredicate"'s predicateWithFormat_("(lastPathComponent BEGINSWITH %@)", replaceText)
set folderTwo to (folderOneContents's filteredArrayUsingPredicate:thePredicate)'s objectAtIndex:0
set folderTwoContents to getFolders(folderTwo)'s valueForKey:"path"
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
repeat with aFolder in folderTwoContents
	(theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:aFolder)
end repeat
(theWorkspace's selectFile:(missing value) inFileViewerRootedAtPath:(folderTwo's |path|()))

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Merge All Windows" of menu "Window" of menu bar 1
end tell

on getFolders(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set folderKey to current application's NSURLIsDirectoryKey
	set packageKey to current application's NSURLIsPackageKey
	set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value)
	set theFolders to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aFolder} to (anItem's getResourceValue:(reference) forKey:folderKey |error|:(missing value))
		if aFolder as boolean is true then
			set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
			if aPackage as boolean is false then (theFolders's addObject:anItem)
		end if
	end repeat
	return theFolders
end getFolders

Compiled as App:

Cannot export as application as the following error is generated:

The document “Test 2.scpt” could not be exported as “Test 2.app”. C and Objective-C pointers cannot be saved in scripts.

Compiling the script will reset property values and may resolve this issue.

Script Editor:

Folder “10 - Description” took about 4-5 seconds; however, it does not open the “10 - Description” folder and only opens a random number of the subfolders such as WA & R or R, T & O.

Folder “549 - Description” took about 4-5 seconds; however, it does not open the “549 - Description” folder and only opens a larger random number of the subfolders such as R ,T, WM & O.

set returnDialog to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set returnedText to text returned of returnDialog

set containFolder to "Volumes:DA2.0:Inventory2:" as alias

tell application "System Events"
	set specf to (first folder of containFolder whose name begins with (returnedText & " - "))
	open specf
	
	set specf to path of specf as alias
	set subf to folders of specf
	
end tell

tell application "Finder" to activate
repeat with eaf in subf
	tell application "System Events"
		keystroke "t" using command down
		set mypath to path of eaf
		tell application "Finder" to set target of front window to mypath
	end tell
end repeat

For testing purposes I created a second folder on the same drive “volumes:DA2.0:Inventory2:”.

This contains 1000 folders. Each folder contains the same seven empty subfolders. These folders are name “1 - Description” to “1000 - Description”.

I am using High Sierra 10.13.6 on a Mac Pro (Mid 2010) 2.8GHz Quad-Core Intel Xeon with four internal hard drives and 48GB of RAM.

The “Open folders in tabs instead of windows” preference is enabled and is found under Finder Preferences on this OS.

The tests are being performed while I have other applications running such as PhotoShop, Illustrator, multiple browsers, OpenOffice and some utility apps like Name Changer and PhotoMill.

Compiled as App:

Folder “10 - Description” took 4 seconds.

Folder “549 - Description” took 4 seconds.

Script Editor:

Folder “10 - Description” took 5 seconds.

Folder “549 - Description” took 5 seconds.

Thanks for your time.

The code provided did not produce any results; however, it worked as a AppleScript after adding the changes peavine suggested.

It does not work as compiled application.

For testing purposes I created a second folder on the same drive “volumes:DA2.0:Inventory2:”.

This contains 1000 folders. Each folder contains the same seven empty subfolders. These folders are name “1 - Description” to “1000 - Description”.

I am using High Sierra 10.13.6 on a Mac Pro (Mid 2010) 2.8GHz Quad-Core Intel Xeon with four internal hard drives and 48GB of RAM.

The “Open folders in tabs instead of windows” preference is enabled and is found under Finder Preferences on this OS.

The tests are being performed while I have other applications running such as PhotoShop, Illustrator, multiple browsers, OpenOffice and some utility apps like Name Changer and PhotoMill.

Compiled as App:

Folder “10 - Description” took 5 seconds, but some of the tabs are randomly showing “Recent”, which is a Finder Preference for new finder windows in this OS.

Folder “549 - Description” took 5 seconds, but some of the tabs are randomly showing “Recent”, which is a Finder Preference for new finder windows in this OS.

Script Editor:

Folder “10 - Description” took 5 seconds.

Folder “549 - Description” took 5 seconds

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")

set replaceText to text returned of theReply2

set theSubs to {"_R", "GS", "K", "O", "T", "WA", "WM"}

set thePath to "DA2.0:Inventory2:"
set theSubFolder to FindFolder(thePath, replaceText & " - ")
if class of theSubFolder = boolean then return
try
	tell application "Finder" to open theSubFolder
on error
	return
end try
repeat with x from 1 to count theSubs
	try
		tell application "Finder" to set theSubSubFolder to folder (item x of theSubs) of theSubFolder
		
		tell application "System Events"
			tell application process "Finder" to set frontmost to true
			keystroke "t" using command down
		end tell
		
		tell application "Finder" to set target of front window to theSubSubFolder
	end try
end repeat

on FindFolder(aFolder, startText)
	local allFolders, folderNames, i
	tell application "Finder"
		tell folders of folder aFolder to set {allFolders, folderNames} to {it, name}
	end tell
	repeat with i from 1 to count folderNames
		if (item i of folderNames) begins with startText then return item i of allFolders
	end repeat
	return false
end FindFolder

Thank you for your time.

For testing purposes I created a second folder on the same drive “volumes:DA2.0:Inventory2:”.

This contains 1000 folders. Each folder contains the same seven empty subfolders. These folders are name “1 - Description” to “1000 - Description”.

I am using High Sierra 10.13.6 on a Mac Pro (Mid 2010) 2.8GHz Quad-Core Intel Xeon with four internal hard drives and 48GB of RAM.

The “Open folders in tabs instead of windows” preference is enabled and is found under Finder Preferences on this OS.

The tests are being performed while I have other applications running such as PhotoShop, Illustrator, multiple browsers, OpenOffice and some utility apps like Name Changer and PhotoMill.

Compiled as App:

Folder “10 - Description” took 4 seconds, buts it opened each folder in a separate window rather than a one window with tabs.

Folder “549 - Description” showed a spinning beach ball in the Finder for 150 seconds before creating a “AppleEvent timed out” error.

Finder got an error: AppleEvent timed out. (-1712)

Script Editor:

Folder “10 - Description” took 5 seconds, buts it opened each folder in a separate window rather than a one window with tabs.

Folder “549 - Description” showed a spinning beach ball in the Finder for 122 seconds before creating a “AppleEvent timed out” error.

tell application "Finder"
	activate
	set {foldersOpenInNewTabs, foldersOpenInNewWindows} to my storeFinderSettings()
	
	set theInventoryPath to "DA2.0:Inventory2:" as alias
	set replaceText to text returned of (display dialog "Enter folder identifier string" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
	set theSubFolder to (first folder of theInventoryPath whose name starts with replaceText & " - ")
	open theSubFolder
	set theSubFolder to (theSubFolder as text)
	
	set theSubSubFolders to {"_R", "GS", "K", "O", "T", "WA", "WM"}
	repeat with indx from 1 to count of items in theSubSubFolders
		open theSubFolder & item indx of theSubSubFolders & ":"
	end repeat
	
	my restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
end tell


on storeFinderSettings()
	tell application "Finder"
		set foldersOpenInNewTabs to folders open in new tabs of Finder preferences
		set foldersOpenInNewWindows to folders open in new windows of Finder preferences
		set folders open in new tabs of Finder preferences to true
		set folders open in new windows of Finder preferences to false
		return {foldersOpenInNewTabs, foldersOpenInNewWindows}
	end tell
end storeFinderSettings
on restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
	tell application "Finder"
		set folders open in new tabs of Finder preferences to foldersOpenInNewTabs
		set folders open in new windows of Finder preferences to foldersOpenInNewWindows
	end tell
end restoreFinderSettings

Thank you for your effort.

For testing purposes I created a second folder on the same drive “volumes:DA2.0:Inventory2:”.

This contains 1000 folders. Each folder contains the same seven empty subfolders. These folders are name “1 - Description” to “1000 - Description”.

I am using High Sierra 10.13.6 on a Mac Pro (Mid 2010) 2.8GHz Quad-Core Intel Xeon with four internal hard drives and 48GB of RAM.

The “Open folders in tabs instead of windows” preference is enabled and is found under Finder Preferences on this OS.

The tests are being performed while I have other applications running such as PhotoShop, Illustrator, multiple browsers, OpenOffice and some utility apps like Name Changer and PhotoMill.

Compiled as App:

Folder “10 - Description” did not work and created the follow error:

Can’t make «class ocid» id «data optr000000000062170080600000» into type alias. (-1700)

With further testing I found that the above error would occur on any folders named “1 - Description” to “100 - Description”, but there was no error on folders named “101 - Description” to “1000 - Description”.

Folder “549 - Description” took 6 seconds but it opened each folder into a separate window instead of a single tabbed window.

Script Editor:

Folder “10 - Description” did not work.

The term “alias” is highlighted in this line of code

open (theSubFolder as alias)

and creates the following error in the Script Editor.

Script Error

Can’t make «class ocid» id «data optr00000000800C570040600000» into type alias.

With further testing I found that the above error would occur on any folders named “1 - Description” to “100 - Description”, but there was no error on folders named “101 - Description” to “1000 - Description”.

Folder “549 - Description” took 7 seconds but it opened each folder into a separate window instead of a single tabbed window.

use scripting additions
use framework "Foundation"

tell application "Finder"
	activate
	set theInventoryPath to "volumes:DA2.0:Inventory2:" as alias
	set findText to text returned of (display dialog "Enter folder identifier string" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
	set theSubFolder to my NSURL_Filename_Contains(my FileSystem_List_Folders(theInventoryPath), findText)
	open (theSubFolder as alias)
	set {foldersOpenInNewTabs, foldersOpenInNewWindows} to my storeFinderSettings()
	set theSubFolder to (theSubFolder as text)
	set theSubSubFolders to {"_R", "GS", "K", "O", "T", "WA", "WM"}
	repeat with indx from 1 to count of items in theSubSubFolders
		open theSubFolder & item indx of theSubSubFolders & ":"
	end repeat
	my restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
end tell

on storeFinderSettings()
	tell application "Finder"
		set foldersOpenInNewTabs to folders open in new tabs of Finder preferences
		set foldersOpenInNewWindows to folders open in new windows of Finder preferences
		set folders open in new tabs of Finder preferences to true
		set folders open in new windows of Finder preferences to false
		return {foldersOpenInNewTabs, foldersOpenInNewWindows}
	end tell
end storeFinderSettings
on restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
	tell application "Finder"
		set folders open in new tabs of Finder preferences to foldersOpenInNewTabs
		set folders open in new windows of Finder preferences to foldersOpenInNewWindows
	end tell
end restoreFinderSettings
on NSURL_Filename_Contains(NSURLArray, matchString)
	set thePredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent CONTAINS %@", matchString)
	return NSURLArray's filteredArrayUsingPredicate:thePredicate
end NSURL_Filename_Contains
on FileSystem_List_Folders(folderObject)
	try
		theFolders of FileSystem_List_Folders_Files_Packages(folderObject)
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_List_Folders>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_List_Folders
on FileSystem_List_Folders_Files_Packages(folderObject)
	try
		set sourceFolderNSURL to FileSystem_Convert_Object_To_NSURL(folderObject)
		set theEntireContents to FileSystem_List_Contents(sourceFolderNSURL)
		set directoryKey to current application's NSURLIsDirectoryKey
		set packageKey to current application's NSURLIsPackageKey
		set theFolders to current application's NSMutableArray's new()
		set theFiles to current application's NSMutableArray's new()
		set thePackages to current application's NSMutableArray's new()
		set booleanTrue to current application's NSNumber's numberWithBool:true
		repeat with thisObject in theEntireContents
			set {theResult, IsADirectory} to (thisObject's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
			if IsADirectory is booleanTrue then
				set {theResult, IsAPackage} to (thisObject's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
				if not (IsAPackage is booleanTrue) then
					(theFolders's addObject:thisObject)
				else
					(thePackages's addObject:thisObject)
				end if
			else
				(theFiles's addObject:thisObject)
			end if
		end repeat
		theFiles's removeObjectsInArray:theFolders
		return {theEntireContents:theEntireContents, theFolders:theFolders, theFiles:theFiles, thePackages:thePackages}
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Unhandled errors in the handler are caught here.
		error "<FileSystem_List_Folders_Files_Packages>" & space & errorText number errornumber partial result errorResults from errorObject to errorExpectedType --Error messages generated in this handler are modified to include the name of the handler. 
	end try
end FileSystem_List_Folders_Files_Packages
on FileSystem_List_Contents(folderObject)
	try
		set folderObject to FileSystem_Convert_Object_To_NSURL(folderObject)
		set theEntireContents to ((current application's NSFileManager's defaultManager's enumeratorAtURL:folderObject includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects())'s mutableCopy()
		return theEntireContents
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_List_Contents>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_List_Contents
on FileSystem_Convert_Object_To_NSURL(fileSystemObject)
	try
		set fileSystemObject to FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
		set fileSystemObject to current application's class "NSURL"'s fileURLWithPath:fileSystemObject
		return fileSystemObject
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Convert_Object_To_NSURL>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Convert_Object_To_NSURL
on FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
	try
		try
			set posixPath to POSIX path of fileSystemObject
		on error
			try
				tell application "System Events"
					set posixPath to POSIX path of ((path of disk item (fileSystemObject as string)) as alias)
				end tell
			on error
				set posixPath to POSIX path of (fileSystemObject as alias)
			end try
		end try
		return current application's NSString's stringWithString:posixPath
	on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
		error "<FileSystem_Convert_Object_To_PosixPath>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
	end try
end FileSystem_Convert_Object_To_PosixPath

tabbyapple. Thanks for testing my new scripts. You previously stated that your target folder contained 300 subfolders, and I hadn’t given any consideration to how my scripts might perform with 1,000 folders.

So, I created a test folder with 1,000 subfolders with 7 folders in subfolders 10 and 549. The timing results on my 2023 Mac mini in seconds were:

Peavine Finder script with folder 10 - 1.4
Peavine Finder script with folder 549 - 38.0
Peavine ASObjC script with folder 10 - 1.4
Peavine ASObjC script with folder 549 - 1.4
tabbyapple script with folder 10 - 1.6
tabgbyapple script with folder 549 - 1.6

All of the scripts worked as written except yours, and I fixed that by adding a 0.1 second delay in the repeat loop.

When all is said and done, my personal preference would be to marry the ASObjC code with the Finder code from my second script in post 3. The timing result with this script was 1.8 second. However, on a 15-year-old computer, your System Events script is certainly a good solution.

use framework "Foundation"
use scripting additions

set folderOne to "/Volumes/Store/Test Folder" --set to desired value
set folderOne to current application's |NSURL|'s fileURLWithPath:folderOne
set newTabDelay to "0.5" --test with smaller values

set theReply2 to (display dialog "Enter new replacement text" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
set replaceText to text returned of theReply2 & " - "

tell application "Finder" to close every window --disable if desired

set folderOneContents to getFolders(folderOne)
set thePredicate to current application's class "NSPredicate"'s predicateWithFormat_("(lastPathComponent BEGINSWITH %@)", replaceText)
set folderTwo to (folderOneContents's filteredArrayUsingPredicate:thePredicate)'s objectAtIndex:0
set folderTwoContents to (getFolders(folderTwo)'s valueForKey:"path")
set folderTwoContents to (folderTwoContents's sortedArrayUsingSelector:"localizedStandardCompare:") as list

tell application "Finder"
	activate
	repeat with aFolder in folderTwoContents
		my newTab(newTabDelay)
		set target of Finder window 1 to POSIX file aFolder
	end repeat
	my newTab(newTabDelay)
	set target of Finder window 1 to POSIX file (folderTwo's |path|() as text)
end tell

on newTab(theDelay)
	tell application "System Events" to tell process "Finder"
		set frontmost to true
		keystroke "t" using command down
	end tell
	delay theDelay
end newTab

on getFolders(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set folderKey to current application's NSURLIsDirectoryKey
	set packageKey to current application's NSURLIsPackageKey
	set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value)
	set theFolders to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aFolder} to (anItem's getResourceValue:(reference) forKey:folderKey |error|:(missing value))
		if aFolder as boolean is true then
			set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
			if aPackage as boolean is false then (theFolders's addObject:anItem)
		end if
	end repeat
	return theFolders
end getFolders

A few comments:

  • I tested the above script with a delay of 0.1 second without issue, but I have set a 0.5 second delay in the above script. Lower delay values can be tested.

  • The above script alphabetically sorts the subfolders before opening them in a Finder window.

  • In my testing, both your and my scripts add the newly opened tabs to an existing Finder window if one is open. I inserted a code line to close any existing Finder windows.

  • When saving an ASObjC script in Script Editor, you will often need to first compile the script with Script > Compile.

  • With macOS Sequoia, saving and running an AppleScript as an application is an exercise in futility, and I have not tested this.

Always interesting to see other’s results tabbyapple! Odd how many errors you received from each script.

This detail is important. My testing environment contains 1000 folders with the naming convention “0001 - Folder Description” or “0741 - Folder Description”. Your environment with un-padded digits prefixes could cause multiple matches for certain search terms.

i.e. ‘50’ will appear multiple times in folder names so ‘50 - Folder Description’, ‘150 - Folder Description’ and ‘250 - Folder Description’ etc would be returned. I don’t see a straightforward work-around for this if you don’t want to offer the user a ‘choose from list’ option ( I know, too many to reasonably use this mechanism ). I’ve tested ‘choose from list’ with the names of the 1000 test sub-folders. It works well enough that I would choose it over the current input-digits-based method.

If your Inventory folder actually contains un-padded, duplicated numerical values then how are these to be definitively selected? i.e. How can the user choose ‘50 - Folder Description’ by inputing just “50”?


The version below opens the sub-folder and all sub-sub-folders ( not limited to the listed standard folders ) simultaneously and in tabs ( Running under AppleScript 2.8, MacOS 15.5 ) and takes on-average 2.5 seconds here in a run of 100 randomized folder selections from a Inventory folder with 1000 sub-folders each containing the 7 listed sub-sub-folders. In testing I saw no errors or open failures over 100 randomly selected folders in multiple runs.

I don’t have a High Sierra OS to test and resolve the opening in tabs there. Here setting the finder preferences after setting ‘System Settings > Desktop & Dock > Prefer tabs when opening documents > ALWAYS’ does create all new finder windows in tabs.

use scripting additions
use framework "Foundation"
    
tell application "Finder"
	activate
	set {foldersOpenInNewTabs, foldersOpenInNewWindows} to my storeFinderSettings()
	set theInventoryPath to (((path to the desktop folder) as alias) as text) & "Inventory:" as alias
	set findText to text returned of (display dialog "Enter folder identifier string" default answer "" buttons {"Cancel", "Continue"} default button "Continue")
	set foldersToOpenList to {(item 1 of (my NSURL_Filename_Contains(my FileSystem_List_Top_Level_Contents(theInventoryPath), findText))) as alias}
	set the end of foldersToOpenList to (every folder of (item 1 of foldersToOpenList)) as alias list
	open foldersToOpenList
	my restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
end tell
    
    
    
    
    
    
    
   

on storeFinderSettings()
    tell application "Finder"
        set foldersOpenInNewTabs to folders open in new tabs of Finder preferences
        set foldersOpenInNewWindows to folders open in new windows of Finder preferences
        set folders open in new tabs of Finder preferences to true
        set folders open in new windows of Finder preferences to false
        return {foldersOpenInNewTabs, foldersOpenInNewWindows}
    end tell
end storeFinderSettings
on restoreFinderSettings(foldersOpenInNewTabs, foldersOpenInNewWindows)
    tell application "Finder"
        set folders open in new tabs of Finder preferences to foldersOpenInNewTabs
        set folders open in new windows of Finder preferences to foldersOpenInNewWindows
    end tell
end restoreFinderSettings
on FileSystem_List_Top_Level_Contents(folderObject)
    try
        set folderObject to FileSystem_Convert_Object_To_NSURL(folderObject)
        set theEntireContents to ((current application's NSFileManager's defaultManager's enumeratorAtURL:folderObject includingPropertiesForKeys:{} options:7 errorHandler:(missing value))'s allObjects())'s mutableCopy() -- options:7 will not recurse
        return theEntireContents
    on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
        error "<FileSystem_List_Top_Level_Contents>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
    end try
end FileSystem_List_Top_Level_Contents
on FileSystem_Convert_Object_To_NSURL(fileSystemObject)
    try
        set fileSystemObject to FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
        set fileSystemObject to current application's class "NSURL"'s fileURLWithPath:fileSystemObject
        return fileSystemObject
    on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
        error "<FileSystem_Convert_Object_To_NSURL>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
    end try
end FileSystem_Convert_Object_To_NSURL
on FileSystem_Convert_Object_To_PosixPath(fileSystemObject)
    try
        try
            set posixPath to POSIX path of fileSystemObject
        on error
            try
                tell application "System Events"
                    set posixPath to POSIX path of ((path of disk item (fileSystemObject as string)) as alias)
                end tell
            on error
                set posixPath to POSIX path of (fileSystemObject as alias)
            end try
        end try
        return current application's NSString's stringWithString:posixPath
    on error errorText number errornumber partial result errorResults from errorObject to errorExpectedType
        error "<FileSystem_Convert_Object_To_PosixPath>" & errorText number errornumber partial result errorResults from errorObject to errorExpectedType
    end try
end FileSystem_Convert_Object_To_PosixPath
on NSURL_Filename_Contains(NSURLArray, matchString)
    set thePredicate to current application's NSPredicate's predicateWithFormat_("lastPathComponent CONTAINS %@", matchString)
    return NSURLArray's filteredArrayUsingPredicate:thePredicate
end NSURL_Filename_Contains

Sorry for responding so late.

The original script with the whose clause was over 32 seconds according to tabbyApple with a folder of over 300 subfolders. On my Mac it was over 35 seconds. But with my edited version, it was 6.9 seconds.