Select Most Recently Created File Within Folders

I have a folder structure with many levels of subfolders.

Via AppleScript, I’d like to be able to have Finder (in one window) select the most recently created file within each folder simultaneously.

I’ve taken a crack at a script of my own.

I seem to be having an issue.

I’m able to “display dialog” every file I want to be accessing, but I am unable to successfully store all those files within a list and select them.

I think my order of operations and my use of recursion isn’t too great - I’ll be the first to admit it :slight_smile:

Any help would be greatly appreciated - thanks very much!

on theSortOut(theMasterFolder)
	
	tell application "Finder"
		
		repeat with aFolder in theMasterFolder as specifier
			
			if class of aFolder is folder then
				
				my theSortOut(aFolder)
				
				set theSort to sort files of aFolder by creation date
				
				display dialog item -1 of theSort as text
				
			end if
			
		end repeat
		
	end tell
	
end theSortOut

--

tell application "Finder"
	
	set theExportsFolder to alias "Macintosh HD:Users:Kevin:Desktop:MASTER-FOLDER"
	
	my theSortOut(theExportsFolder)
	
end tell

If I understand correctly, you may use :

on theSortOut(theMasterFolder)
	
	tell application "Finder"
		
		repeat with aFolder in theMasterFolder as specifier
			
			if class of aFolder is folder then
				
				my theSortOut(aFolder)
				
				set theSort to sort files of aFolder by creation date
				
				select item -1 of theSort
			end if
			
		end repeat
		
	end tell
	
end theSortOut

--

tell application "Finder"
	
	set theExportsFolder to alias ((path to desktop as text) & "MASTER-FOLDER")
	open theExportsFolder
	tell Finder window 1 to set current view to column view
	
	my theSortOut(theExportsFolder)
	
end tell

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 25 octobre 2019 17:31:44

Thanks for your reply!

The script you supplied made it so each file would open in its own separate Finder window, whereas I’m aiming for the script to select all of the appropriate Finder items within just one Finder window.

Do you think while in the repeat statement I’d be able to trap each “item -1 of theSort” into a list in order to use it outside of the repeat?

Thanks again!

That’s simply not possible. And it’s how Finder works, not a limitation of AppleScript.

Building that list is not the issue - it’s really what you want to do with them. Just selecting umpteen files does not seem very useful. There may be an entirely different way to get to your desired result.

It is possible:


global aSelection

on run
	set theExportsFolder to choose folder
	set aSelection to {}
	
	tell application "Finder"
		activate
		open theExportsFolder
		tell Finder window 1 to set current view to column view
		set subFolders to folders of theExportsFolder
	end tell
	
	repeat with aFolder in subFolders
		my sortOut(aFolder)
	end repeat
	
	-- Then, you can process selection as you want, for example:
	-- repeat with aFile in aSelection
		-- tell application "Finder"
			-- select aFile
			-- delay 1
			-- close container window of container of aFile
		-- end tell
	-- end repeat
	
	return aSelection
end run


on sortOut(aFolder)
	tell application "Finder"
		if (count of (files of aFolder)) > 0 then
			set theSort to sort files of aFolder by creation date
			set end of aSelection to last item of theSort
		end if
		set subFolders to folders of aFolder
		repeat with aFolder in subFolders
			my sortOut(aFolder)
		end repeat
	end tell
end sortOut

NOTE: To show selection’s files selected in 1 window, they must be in 1 folder. So, you can 1) create temporary folder 2) duplicate selection’s files to this folder 3) select and show them by Finder 4) delete temporary folder. For example, replace commented piece of code above with this:


        set tempFolder to path to desktop folder
	tell application "Finder"
		set newFolder to make new folder at tempFolder with properties {name:"mySelectedFies"}
		repeat with aFile in aSelection
			try
				set newFile to duplicate aFile to newFolder
			end try
			select files of newFolder
		end repeat
		delay 5
		delete newFolder
	end tell

But, as I think, aSelection list is all you need to process this files further… And, if you need choose some of this files further you can show them to user into 1 choose from list dialog:


global aSelection

on run
	set theExportsFolder to choose folder
	set aSelection to {}
	tell application "Finder"
		activate
		open theExportsFolder
		tell Finder window 1 to set current view to column view
		set subFolders to folders of theExportsFolder
	end tell
	repeat with aFolder in subFolders
		my sortOut(aFolder)
	end repeat
	tell me to activate
	choose from list aSelection
end run

on sortOut(aFolder)
	tell application "Finder"
		if (count of (files of aFolder)) > 0 then
			set theSort to sort files of aFolder by creation date
			set end of aSelection to POSIX path of ((last item of theSort) as alias)
		end if
		set subFolders to folders of aFolder
		repeat with aFolder in subFolders
			my sortOut(aFolder)
		end repeat
	end tell
end sortOut

Exactly! But that was not what he asked; he wanted a selection in multiple folders in one window. And that is not possible.

Also, he seemed convinced he had to make that impossible selection, but did not tell us what his goal was. I believe it’s better to let him explain first, and then help him achieve a workable solution.

This uses ASObjC methods to identify the files because the Finder was taking rather a long time on my machine. The trick here is to open a list-view window on the top folder, fully expand all the subfolders, and select the identified files using ‘set selection’ rather than ‘select’. It works OK on my machine, but may need a delay at the end of the expandSubfolders() handler if the expansion’s not getting completed before the script tries to select the files.

use AppleScript version "2.5" -- El Capitan (10.11) or later
use scripting additions

selectMostRecentFiles()

on selectMostRecentFiles()
	tell application "Finder"
		activate
		set topFolder to (choose folder with prompt "Select a folder….")
		tell (make new Finder window to topFolder) to set its current view to list view
	end tell
	
	expandSubfolders()
	set mostRecentFiles to getMostRecentFiles(topFolder)
	
	tell application "Finder" to set selection to mostRecentFiles -- NB. 'set selection' here, not 'select'.
end selectMostRecentFiles

on expandSubfolders() -- Expand all folders in a list-view window.
	tell application "System Events"
		tell application process "Finder" to set frontmost to true
		keystroke "a" using {command down} -- Select everything in the window.
		key code 124 using {command down, option down} -- Expand the folders. (Command-Option-right arrow.)
	end tell
	-- Hopefully the folders will be fully expanded before the handler below has worked out what to select.
	-- If not, add a delay here.
end expandSubfolders

on getMostRecentFiles(topFolder)
	script o
		use framework "Foundation"
		
		property |⌘| : current application
		property fileManager : missing value
		property skipHiddenFiles : missing value
		property creationDateKey : missing value
		property allKeys : missing value
		property directoryKeys : missing value
		property directoryResult : missing value
		property mostRecentFiles : {}
		
		on init() -- Initialise some ASObjC values.
			set fileManager to |⌘|'s class "NSFileManager"'s defaultManager()
			set skipHiddenFiles to |⌘|'s NSDirectoryEnumerationSkipsHiddenFiles
			set directoryKey to |⌘|'s NSURLIsDirectoryKey
			set packageKey to |⌘|'s NSURLIsPackageKey
			set creationDateKey to |⌘|'s NSURLCreationDateKey
			set allKeys to |⌘|'s class "NSArray"'s arrayWithArray:({directoryKey, packageKey, creationDateKey})
			set directoryKeys to |⌘|'s class "NSArray"'s arrayWithArray:({directoryKey, packageKey})
			set directoryResult to |⌘|'s class "NSArray"'s arrayWithArray:({true, false})
		end init
		
		on gmrf(thisFolder) -- Recursive handler.
			-- Get the contents of the current folder.
			set theseContents to fileManager's contentsOfDirectoryAtURL:(thisFolder) includingPropertiesForKeys:(allKeys) options:(skipHiddenFiles) |error|:(missing value)
			-- Initialise a collector for the URLs and creation dates of the files (including packages).
			set fileData to |⌘|'s class "NSMutableArray"'s new()
			repeat with thisURL in theseContents
				set resourceValues to (thisURL's resourceValuesForKeys:(allKeys) |error|:(missing value))
				-- Does this URL represent a directory? (42's just a convenient placeholder and has no significance here.)
				if ((resourceValues's objectsForKeys:(directoryKeys) notFoundMarker:(42))'s isEqualToArray:(directoryResult)) then
					-- If it does, check out the directory's contents recursively.
					gmrf(thisURL)
				else
					-- Otherwise get the file's creation date.
					set thisDate to (resourceValues's valueForKey:(creationDateKey))
					-- Add a dictionary containing the URL and it to the current data collector.
					set aDict to (|⌘|'s class "NSDictionary"'s dictionaryWithObjects:({thisURL, thisDate}) forKeys:({"URL", "creationDate"}))
					tell fileData to addObject:({|URL|:thisURL, creationDate:thisDate})
				end if
			end repeat
			if ((count fileData) > 0) then
				-- If any data have been collected when all this folder's URLs have been checked, get the most recent creation date.
				set mostRecentDate to fileData's valueForKeyPath:("@max.creationDate")
				-- Reduce the data to just the one or more dictionaries containing this date.
				set filter to |⌘|'s class "NSPredicate"'s predicateWithFormat_("creationDate == %@", mostRecentDate)
				tell fileData to filterUsingPredicate:(filter)
				-- Derive file specifier(s) from the corresponding URL(s) and concatenate these to the output list.
				set mostRecentFiles to mostRecentFiles & (fileData's valueForKey:("URL")) as list
			end if
		end gmrf
	end script
	
	tell o
		init()
		gmrf(topFolder)
		return its mostRecentFiles
	end tell
end getMostRecentFiles