How To Get Path to Finder Folder or Target of Window

how-to
finder

(Jim Underwood) #1

I’ve been asking a lot of questions, and getting a lot of help, recently in this forum. So I thought I’d try to give back a little.

Many of you may already know how to do this, but if you’re like me it may not be so obvious. I continue to struggle with the multiple forms of file/folder paths in AppleScript.

One great thing about ASObjC is almost always it use, or can use, a POSIX path as a parameter. Sometimes, you might like to operate on either a folder that is selected in the Finder, OR, if none are selected, use the target of the Finder window. That’s exactly what this script does.

AppleScript To Get Path to Finder Folder or Window Target

tell application "Finder" to set fItemList to (selection as alias list)

if ((count of fItemList) = 0 or (kind of (info for (item 1 of fItemList)) ≠ "folder")) then
  tell application "Finder" to set fItemPath to POSIX path of (target of front window as text)
else
  set fItemPath to POSIX path of (item 1 of fItemList)
end if

BTW, yes I know that info for has been deprecated. But that was years ago, and it still seems to be alive and well. Until it dies, I will continue to use it. :wink:

If you prefer not to use it, please feel free to post a version using alternate commands.


(CK) #2

Thanks for this, @JMichaelTX. I really like the random “How-To” posts that appear on this forum.

Incidentally, info for has a property called folder that has a value of true or false according to whether or not a given file reference is a folder. So you could use the expression

(info for (item 1 of fItemList)) ≠ folder

if you wanted, not that it confers much difference or particular benefit.

One change I would make would be to specify the front window in Finder as being specifically the front Finder window, i.e.

POSIX path of (target of front Finder window as text)

which ensures you’ll not inadvertently be attempting to retrieve the target of an information panel or the properties window.

Then I realised that the script would throw an error in the absence of any Finder windows (regardless of how one references these windows). So I considered the nature of Finder’s insertion location property, which typically points to the same place as the target of the front Finder window if one exists, or the Desktop if not. I thought I’d offer it up as a possibility:

use F : application "Finder"

tell (F's selection as list) ¬
	to if (count) is 1 ¬
	and the first item's class is folder ¬
	then return the POSIX path ¬
	of (the first item as alias)

POSIX path of (insertion location as alias)

System info: AppleScript version: "2.7", system version: "10.13.3"

Summary

An AppleScript to retrieve the POSIX path of the currently selected folder in Finder if (precisely) one is, indeed, selected, otherwise defaulting to the POSIX path of Finder’s insertion location, which itself will point to the folder opened in Finder’s frontmost window, defaulting to the desktop folder if no Finder windows are currently open.

If the desktop folder isn’t a desirable default, the following few lines could be inserted at the start of the above script to provide a way of specifying a preferred default:

use F : application "Finder"

property home : container of desktop as alias
property desktop : F's desktop as alias
property default : a reference to home

if not (some Finder window exists) then return the default's POSIX path

(Jim Underwood) #3

Thanks for sharing. It’s always good to see another perspective, and potential improvements.


(Nigel Garvey) #4

Hi. This errors on my system. It should be:

not (info for (item 1 of fItemList))'s folder

Or preferably, for reading purposes:

not ((info for (item 1 of fItemList))'s folder)

Here are a couple more variations on the script, one using info for, the other just the Finder. The info for one allows for the possibility that the selected item’s a package, treating it as a file. Both allow for the insertion location and the frontmost Finder window not necessarily being the same, favouring the Finder window.

Using info for:

tell application "Finder" to set fItemList to (selection as alias list)

if (fItemList is {}) then
	set folderSelected to false
else
	set fItem to item 1 of fItemList
	tell (info for fItem) to set folderSelected to (folder ≠ package folder)
end if
if (folderSelected) then
	set fItemPath to POSIX path of fItem
else
	tell application "Finder"
		if (Finder window 1 exists) then
			set fItemPath to POSIX path of ((target of Finder window 1) as alias)
		else
			set fItemPath to POSIX path of (insertion location as alias)
		end if
	end tell
end if

Using just the Finder:

tell application "Finder"
	set fItemList to selection
	if (fItemList is {}) then
		set folderSelected to false
	else
		set fItem to item 1 of fItemList
		set folderSelected to (fItem's class is folder)
	end if
	if (folderSelected) then
		set fItemPath to POSIX path of (fItem as alias)
	else if (Finder window 1 exists) then
		set fItemPath to POSIX path of ((target of Finder window 1) as alias)
	else
		set fItemPath to POSIX path of (insertion location as alias)
	end if
end tell

(Jim Underwood) #5

Nigel, thanks for sharing. I always like to see your take on a script.

Putting aside who wrote the above scripts, would you mind commenting on whether one or the other offers advantages or limitations over the other?

I would ask you to choose the best script, but Shane might jump on me. :wink:

Thanks.


(Nigel Garvey) #6

I wouldn’t blame him. :wink: It’s not for me to adjudicate. But to comment on perceived advantages and limitations:

Your script’s one you’ve written to automate something you do on your own computer. You wrote it yourself and it does what you want, so if you’re interested in scripting, you should perhaps use it just for the sheer satisfaction of knowing that. You can always modify it later if the need or the fancy takes you, or if you like any of the points raised in this thread.

CJK’s script doesn’t assume that only one item will be selected, or that the Finder will have any windows open, or that any of them will be Finder windows. It also doesn’t use info for, which — as you said yourself — is deprecated. So from the point-of-view of a script which may have to run on other people’s machines for some time into the future, his is an improvement over yours. I personally disapprove of his use of use with applications and the unnecessary one-lining of most of the code, but it’s not illegal and the script works.

My scripts go a stage further and cater for a situation I noticed when testing CJK’s script: that the frontmost Finder window isn’t necessarily the insertion location. On the other hand, both scripts revert to your assumption that only one item will be selected. :confused: The info for version, I now think, is largely a waste of space. It was written because I was distracted by CJK’s suggestion for using info for's folder property, which is also true when the item’s a package. But I think your own use of the kind property gets round this — unless a word other than “Folder” is returned on non-English systems. Of my two scripts, I prefer the Finder-only one, although modified as below to accept only a one-item selection as valid:

tell application "Finder"
	set fItemList to selection
	if ((count fItemList) is 1) then
		set fItem to item 1 of fItemList
		set folderSelected to (fItem's class is folder)
	else
		set folderSelected to false
	end if
	if (folderSelected) then
		set fItemPath to POSIX path of (fItem as alias)
	else if (Finder window 1 exists) then
		set fItemPath to POSIX path of ((target of Finder window 1) as alias)
	else
		set fItemPath to POSIX path of (insertion location as alias)
	end if
end tell

(Jim Underwood) #7

Thanks for taking the time for such a thorough analysis and reporting. I always learn a lot from your insights. I think this will be a big help to others who read this thread.


(CK) #8

Thank you, @NigelGarvey, for highlighting this. I missed it on my proof-read. It was a typo in the form of a mis-placed parenthesis. I’ve made the correction to my original post, which now reads as:

(info for (item 1 of fItemList)) ≠ folder

mirroring the source from which the suggestion stems.


By the way, your deconstruction of the various scripts contributed thus far is excellent. I take your point about my particular style of AppleScript coding, which I presume from the counter-justification, relates to its readability and/or aesthetics. You aren't the first to remark on this, and I can understand why one might find it objectionable.

Specifically, what about my use statement do you disapprove of ? I’m asking as a point of advice, in case there’s something in its implementation I’ve failed to consider or need to know more about. You’re welcome to send any comments to me in a personal message if you prefer, but hopefully the small digression off-topic won’t hurt this thread.

Oh! Another point of note for me: can you tell me when the insertion location wouldn’t point to the same location as the front Finder window's target ? I think this would be useful for me to know. Adding to this, are there situations where the desktop doesn’t become the insertion location if no Finder window exists ?


(Jim Underwood) #9

Thanks again.

I’ve revised my script to address these issues:

Done. Changed to
tell application "Finder" to set fItemPath to POSIX path of (target of Finder window 1 as text)

Actually, it is not an assumption. It is agnostic.
I don’t care how many items are selected, only that at least one was, and I use the first item.
I often use this approach. Am I missing something?

Done. I made use of your approach to compare info for “folder” with “package folder”:
if (fItemList ≠ {}) then tell (info for (item 1 of fItemList)) to set isFolder to (folder ≠ package folder)

Sorry, but I continue to really like info for. I have tested it extensively and it is faster and easier to use than any other command I know of.
Maybe one day Apple will bite me – I’ll deal with it then. :wink:

Here’s my complete, improved thanks to you, revised script:

tell application "Finder" to set fItemList to (selection as alias list)
if (fItemList ≠ {}) then tell (info for (item 1 of fItemList)) to set isFolder to (folder ≠ package folder)

if ((fItemList) = {} or (isFolder is false)) then
  tell application "Finder" to set fItemPath to POSIX path of (target of Finder window 1 as text)
else
  set fItemPath to POSIX path of (item 1 of fItemList)
end if

Nigel, although I have no doubt that your final Finder script is the best, I do like my revised script because it is compact while still readable.


(Shane Stanley) #10

Let me buy in here. You’re opening yourself to host of pain as soon as a script starts using more than one application. AppleScript implementors are encouraged to use common suites of terms, and once you make them global you can get all sorts of conflicts. There’s no rule on priority.

As a matter of style, I think it also makes scripts of any length significantly harder to follow.

I don’t see how this gains anything over using Standard Additions’s path to command. It also makes the script non-portable, in the sense that you’re baking in the home and desktop aliases at compile time.


(Nigel Garvey) #11

I date from before the use command was introduced. :wink: I think it’s fine for loading libraries or specifying minimum versions, but don’t (personally) think using it to load applications’ scripting terminologies does anything to aid clarity in a script. It’s not too bad in a short script like yours. But say someone reading a long script not written by them (or which was written by them several months earlier) comes across F's selection as list somewhere in the middle, where the use instructions are off the top of the screen, they have to scroll back up the script to find out what this F is that owns a selection.

The above isn’t a good example, but you can see how things might develop. F could be one of several applications addressed by the script, or maybe a library script with its own terminology. It’s much clearer to address an application explicitly (where practical) so that a reader can see where the terminology’s coming from. It’s there on the screen staring you in the face — even if the contents of the tell statement are then one-lined. :wink:

tell application "Finder"
	tell (its selection as list) ¬
		to if (count) is 1 ¬
		and the first item's class is folder ¬
		then return the POSIX path ¬
		of (the first item as alias)
	
	POSIX path of (insertion location as alias)
end tell

POSIX path isn’t a Finder term, of course. But hey.

I see Shane’s replied more succinctly. :slight_smile:

If you open a Finder window but then click the desktop (or select something on it), the insertion location will be the desktop.


(Nigel Garvey) #12

I think I must be. The script makes a decision based on the class of the first item in the selection. Presumably this is important. If several items are selected, you can’t be sure which will be the first in the list.

:slight_smile:

… but it does still assume there’ll be a Finder window open.


(Jim Underwood) #13

I thought that the first item in the Finder’s selection is always the first item as shown in the Finder window where the items are selected. Is this incorrect?

Perhaps, but you get an error if not window. So if the user has instructions to select a folder, an item in a window, or a window, and does none of those, seems like an error is in order. But that’s just me.

For a production script, I would include an error handler.


(Nigel Garvey) #14

Hmm. This seems to be true, trying it out this morning on my High Sierra Machine with a variety of views and sort orders — except where icons have been dragged around in icon view. But it’s not something I’d have assumed based on past experience.


(Shane Stanley) #15

FWIW, that pretty much matches my reaction. I can definitely remember that it certainly wasn’t the case at one point.


(Jim Underwood) #16

Isn’t it great when Apple just changes stuff without notice.

OTOH, this happens to be a good change, to one which, IMO, is logical.

Since you guys are running HS, I’ll test it on LS (Sierra).


(CK) #17

OK, that’s fine, I was aware of this. In fact, for the ways in which I would wish the script to be implemented for my personal use, it was another reason I opted to use insertion location: if I were to select a folder on the desktop and then run the script, I would be irked if it, say, opened a Terminal window pointing at the target of some Finder window sitting off to the side that I wasn’t actively working in. But I think it’s going to be an individual’s working habits that determine best what ought to take precedence for them.

Thank you for explaining your views on the use construct. You and @ShaneStanley both articulated the potential pitfalls nicely, and the insight offered is great. Thanks to you both for taking the time to explain.


(Jean Christophe Helary) #18

But then, the window is not the “front” window is it? It may not be visually “behind” the desktop, but it is for all other practical purposes isn’t it?


(Nigel Garvey) #19

Jim’s original script returned the path to a selected folder if the folder was the first item in the selection, or to the target of the front window otherwise. The only windows the Finder has with target properties are those of class Finder window, so that’s the type of window implied.

CJK suggested getting the Finder’s insertion location instead in case there were no Finder windows open, so that the script would then return the path to the desktop instead of erroring. The assumption was that if any Finder windows were open, the front one would be the insertion location. I was pointing out that this isn’t necessarily the case.


(Jean Christophe Helary) #20

Thank you. I got lost into the thread at some point… :frowning: