Delete other files with the exact same size.

Ah yes. I’d overlooked them in my script. System Events includes invisibles when returning disk items. While the Finder will error if specifically asked to return those invisibles, it seems it will delete them if passed their paths in a list.

My script can easily be adapted in either of two ways, depending on which seems the best idea at the time. One is to get the files’ ‘visible’ properties too and eliminate any paths where the corresponding ‘visible’ is false:

use sorter : script "Custom Iterative Ternary Merge Sort" -- <https://macscripter.net/viewtopic.php?pid=194430#p194430>
use scripting additions

on main()
	script o
		property filePaths : missing value
		property fileSizes : missing value
		property fileVisibles : missing value
	end script
	
	set thePath to (choose folder) as text
	-- Get corresponding lists of the folder's files' paths, sizes, and visibles. System Events is faster than the Finder for this.
	tell application "System Events" to set {o's filePaths, o's fileSizes, o's fileVisibles} to {path, size, visible} of files of folder thePath
	
	-- Sort all three lists on the files' paths (can be omitted), then (stably) on the sizes.
	tell sorter to sort(o's filePaths, 1, -1, {slave:{o's fileSizes, o's fileVisibles}}) -- If desired.
	tell sorter to sort(o's fileSizes, 1, -1, {slave:{o's filePaths, o's fileVisibles}})
	-- Initialise a "current size" variable to some figure below the lowest size.
	set currentSize to (beginning of o's fileSizes) - 1024
	-- Work through the visibles and sizes. At each non-visible or size increase, replace the corresponding path with missing value.
	repeat with i from 1 to (count o's fileVisibles)
		if (item i of o's fileVisibles) then -- visible = true.
			set thisSize to item i of o's fileSizes
			if (thisSize > currentSize) then
				set item i of o's filePaths to missing value
				set currentSize to thisSize
			end if
		else -- visible = false.
			set item i of o's filePaths to missing value
		end if
	end repeat
	
	-- Get a list containing only the unreplaced paths and bulk-delete those files.
	-- The Finder accepts list of paths for this. System Events's dictionary says it does too, but it doesn't accept lists of anything on my machine.
	set filesToDelete to o's filePaths's text
	tell application "Finder" to delete filesToDelete
	
	return
end main

main()

Or, if you take invisible files simply as those whose names begins with “.”, and you’re only searching one folder, the paths to such files will be sorted to the beginning when the paths are sorted and so they can be eliminated then:

use sorter : script "Custom Iterative Ternary Merge Sort" -- <https://macscripter.net/viewtopic.php?pid=194430#p194430>
use scripting additions

on main()
	script o
		property filePaths : missing value
		property fileSizes : missing value
	end script
	
	set thePath to (choose folder) as text
	-- Get corresponding lists of the folder's files' paths and sizes. System Events is faster than the Finder for this.
	tell application "System Events" to set {o's filePaths, o's fileSizes} to {path, size} of files of folder thePath
	
	-- Sort both lists on the files' paths.
	tell sorter to sort(o's filePaths, 1, -1, {slave:{o's fileSizes}})
	set numberOfFiles to (count o's filePaths)
	-- Replace paths containing ":." with missing value. In a single-level hierarchy, these will have been sorted to the beginning of the path list.
	repeat with i from 1 to numberOfFiles
		if (item i of o's filePaths contains ":.") then
			set item i of o's filePaths to missing value
		else
			exit repeat
		end if
	end repeat
	
	-- If there are at least two visible paths left …
	if (i < numberOfFiles) then
		-- Sort the corresponding items in both lists on the files' sizes.
		tell sorter to sort(o's fileSizes, i, -1, {slave:{o's filePaths}})
		-- Initialise a "current size" variable to some figure below the lowest size.
		set currentSize to (item i of o's fileSizes) - 1024
		-- Work through the sizes. At each increase, replace the corresponding path with missing value.
		repeat with i from i to numberOfFiles
			set thisSize to item i of o's fileSizes
			if (thisSize > currentSize) then
				set item i of o's filePaths to missing value
				set currentSize to thisSize
			end if
		end repeat
		
		-- Get a list containing only the unreplaced paths and bulk-delete those files.
		-- The Finder accepts list of paths for this. System Events's dictionary says it does too, but it doesn't accept lists of anything on my machine.
		set filesToDelete to o's filePaths's text
		tell application "Finder" to delete filesToDelete
	end if
	
	return
end main

main()

Shane, thanks again for clarification. I will convert your script into a recursive version to remove any duplicates on my home folder.

I already have one unusual script https://www.macscripter.net/viewtopic.php?id=46812 that I wrote using Smart Folders future. It is as fast as possible and it will be interesting for me then to compare it with your script.

Shane Stanley recently posted another Script Geek update, and I remembered this topic. Nigel Garvey managed to get a code that was slightly faster than the code published by Peavine. Then I didn’t have a Script Geek to test it out and I took their word for it.

Now I have Script Geek . I also remembered that:

  1. the Peavine code contained an unnecessary repeat loop and its speed could be improved further. 2) I also introduced another improvement by applying the contents (of current item) property in the second (necessary) loop, which is speed efficient.

Thus, I was able to get the code 1.5 times faster than the Peavine’s original. For clarity, I removed the warning dialogs. Now, it is as fast as it is simple. Which is what I try to achieve for every “good” script.


set sourceFolder to choose folder

tell application "Finder"
	set theFiles to every file in sourceFolder as alias list
	set fileSizes to size of every file in sourceFolder
end tell

set previousFileSizes to {}
set deleteList to {}
set i to 0
repeat with theSize in fileSizes
	set i to i + 1
	if (theSize is in previousFileSizes) then
		set end of deleteList to item i of theFiles
	else
		set end of previousFileSizes to contents of theSize
	end if
end repeat

-- tell application "Finder" to delete deleteList