Surely this has been asked and answered a thousand times by now.
But after extensive searching, I’ve not found a good answer.
Would one of you AppleScript gurus mind sharing your solution?
Here’s what I have, which works fine for small selections. But I suspect it would be slow for large selections. It just seems like we should be able to get this with one command.
tell application "Finder"
set itemList to the selection
## FAILS ##
--set itemNameList to name of every item in Selection
set itemNameList to my getItemName(itemList)
end tell
on getItemName(pFinderItemOrList)
if (class of pFinderItemOrList is list) then
set nameList to {}
repeat with iItem in pFinderItemOrList
set end of nameList to (name of iItem)
end repeat
return nameList
else
return name of pFinderItemOrList
end if
end getItemName
You can’t. The selection in the Finder is not really an object you can work with. It’s basically a command that returns a result.
NOTE: – ALWAYS get the selection as alias list (or as text). The bare form produces Finder references and is significantly slower.
Testing with a selection of 500 items:
----------------------------------------------------------------------
set nameList to {}
tell application "Finder"
set fSelection to selection as alias list
repeat with f in fSelection
set end of nameList to name of f
end repeat
end tell
--> 3 seconds (with as alias list)
--> 9+ seconds (without as alias list)
----------------------------------------------------------------------
set AppleScript's text item delimiters to linefeed
tell application "Finder"
set fSelection to selection as text
end tell
set nameList to paragraphs of cng("^.+:([^:]+):?$", "\\1", fSelection) of me
# OR using the Satimage.osax instead of paragraphs
# set nameList to fnd("^\\S.*$", nameList, true, true) of me
--> 0.2 seconds (without converting to list)
--> 0.95 seconds (with converting to list)
----------------------------------------------------------------------
--» HANDLERS
----------------------------------------------------------------------
# REQUIRES: Satimage.osax
----------------------------------------------------------------------
on cng(_find, _replace, _data)
change _find into _replace in _data with regexp without case sensitive
end cng
----------------------------------------------------------------------
Chris, I was hoping that you might respond to this.
Thanks for the definitive answer. This should be posted in a very prominent place somewhere. It is a basic tip that all users of AppleScript should be aware of.
I keep thinking that we (all AppleScript users) really need an AppleScript Wiki that is well supported by guys like you, Shane, Mark, and others here and on the ASUL.
I’d be glad to serve as the admin of such a wiki if you guys are interested.
I only have a variant on yours, but essentially the same thing, looping through the selection and getting the name property.
set nameList to {}
tell application "Finder"
set s to (get selection)
repeat with i from 1 to count of s
set this_item to item i of s
set end of nameList to this_item's name
end repeat
end tell
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
property NSString : a reference to current application's NSString
# property NSArray : a reference to current application's NSArray
tell application "Finder"
set fSelection to selection as text
set parentF to insertion location as text
end tell
set aString to NSString's stringWithString:fSelection
set anArray to (aString's componentsSeparatedByString:parentF) as list
Of course, speed isn’t the only factor - it also depends on what the user wants to do with that list. One thing I don’t like about getting the selection as text is you end up with the colon separated path forms, which might slow you down later if you need to convert them to something else.
I didn’t want to bring that up because it wasn’t Jim’s question, but my initial thought here was: well, I wouldn’t use the Finder to get files names into a script in the first place, and certainly not for huge lists of them. But without knowing the purpose, it’s impossible to suggest an alternative.
But if you’re going to then do something with the files whose names are chosen in the dialog, you don’t need just the list of names – you need parallel lists of the names and the files, so you can match them up when the user’s choice has been made. That’s what I meant by not wanting “just the names”.
And what you intend to do with the files might well be the more important factor in how you get the original list, and hence the names, from the Finder. For example, if you intend to pass them to an application to open, then you probably want them as an alias list; if you intend to pass them to System Events, you might want them as simple paths. You certainly don’t want them as Finder references unless you’re going to be doing something with them in the Finder anyway.
I guess I’m saying that in the real world, chances are the best choice depends on what else you’re doing, because in that context you’re not really getting just the names.
But I need just the item names for the choose from list.
So, what solution do you propose that would allow me to do that, and then use, say the POSIX path, for the item based on the user’s choices?
Unless there are likely to be a very large number involved, Chris’s first option in the first reply should be fast enough – I don’t see any need to make it more complicated. Then you can use the POSIX path property of the alias(es) in the alias list.
Thanks, Shane, but I’m not sure you really answered my question.
While Chris’ option is faster, it is functionally the same as my original post.
I guess I thought you had some cool way of showing the user a simple list of item names, and then based on his/her selection, get the path to the item. AFAIK, the only way to do this is by determining the position in the list of the user’s choice, and then using that as an index into the path list.
It’s not really the same, because it gives you a list of aliases rather than a list of Finder references. That’s a significant difference when it comes to using the results.
There’s no magic.
Pretty much. There are other ways, but they’re contrived. For example:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use theLib : script "Myriad Tables Lib" version "1.0.7"
use scripting additions
set nameList to {}
tell application "Finder"
set fSelection to selection as alias list
repeat with f in fSelection
set end of nameList to name of f
end repeat
end tell
set theInfo to swap columns and rows in {nameList, fSelection}
set theResult to display table with data theInfo row template {text, missing value} with prompt "Pick a file" with double click means OK
set theFile to item 2 of item 1 of values selected of theResult