AppleScript: filter an existing Finder selection by file type, or part of file name

I would like to be able to filter an existing Finder selection through AppleScript, using the name extension or a substring of the file name.
I can't make this simple code to work, which is quite frustrating:

tell application "Finder"
set lsFiles1 to selection
set lsFiles to (every item of lsFiles1 whose name ends with "dmg")

-- it could have been
-- set lsFiles to (every item of lsFiles1 whose name contains "abcde")

end tell

What am I doing wrong?

Thank you,

Does it have to be AppleScript, or are you open to other solutions?


Hey rob, I would like to do it in AppleScript, as it is just a small part of the code.
Besides that, I know I could loop through the list and check every item name, but I'd like to understand what's wrong in the above syntax.

Thank you!

It's just a type issue – the selection object returned by Finder happens to be a list, rather than a reference to a collection.

i.e. you would have to work through the list items one by one, rather than applying some whose | where magic.

This kind of thing is possible, but it may be more involved than you need (a simple loop and test would be enough):

Expand disclosure triangle to view AppleScript source
tell application "Finder"
	set xs to selection
	script f
		on |λ|(x)
			if name of x ends with "dmg" then
				{POSIX path of (x as alias)}
			end if
		end |λ|
	end script
	my concatMap(f, xs)
	-- or just a filter with a predicate
	-- 	script p
	-- 		on |λ|(x)
	-- 			name of x ends with "dmg"
	-- 		end |λ|
	-- 	end script
	-- 	my filter(p, xs)
end tell

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
	set lng to length of xs
	set acc to {}
	tell mReturn(f)
		repeat with i from 1 to lng
			set acc to acc & (|λ|(item i of xs, i, xs))
		end repeat
	end tell
end concatMap

-- filter :: (a -> Bool) -> [a] -> [a]
on filter(p, xs)
	tell mReturn(p)
		set n to length of xs
		set ys to {}
		repeat with i from 1 to n
			set v to item i of xs
			if |λ|(v, i, xs) then set end of ys to v
		end repeat
	end tell
end filter

-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
	-- 2nd class handler function lifted into 1st class script wrapper. 
	if script is class of f then
			property |λ| : f
		end script
	end if
end mReturn

And I think files of target of front window may be closer to what you want:

tell application "Finder"
	tell target of front window
		files where name ends with "dmg"
	end tell
end tell

( but it involves no semantics of selection )


You indeed know AppleScript (and JavaScript), ComplexPoint. Thank you!!!

Checking your code, I ended up with a simpler solution, otherwise debugging at later times would have been impossible, given my limited understanding of AS.
Should it be of help, here it is:

set lsFiles to {}
tell application "Finder"
set lsFiles1 to selection as alias list
repeat with sFile in lsFiles1
if name extension of sFile is "dmg" then set lsFiles to lsFiles & sFile
end repeat
end tell

Thanks for the help,

1 Like