Alias from item that does not exist


(Ed Stockly) #1

Is this new? If I try to coerce text to an alias to an item that does not exist because the startup drive is missing from the front of the the text string, appleScript “helpfully” adds the startup disk to the string. Took me quite a while to figure out why I was getting this behavior.

The ASLG says: “HFS paths with a leading colon, such as “:folder:file”, are resolved relative to the HFS working directory. However, their use is discouraged, because the location of the HFS working directory is unspecified, and there is no way to control it from AppleScript.”

But the string in this script (below) doesn’t have a leading colon.

Is this a bug?

set partialPath to "Library:Scripts:"
tell application "Finder"
   set isPathGood to exists item partialPath -- false
end tell
set aliasFromPartialPath to partialPath as alias
--alias "Macintosh HD:Library:Scripts:"

(Shane Stanley) #2

If you mean is it recent, I suspect not. POSIX path has always exhibited the same behavior, and they probably use similar approaches.

It’s academic at this stage – HFS paths are deprecated, and nothing to do with them is likely to change. But it certainly supports Chris Nebel’s objection to using as alias as a way to verify that a file exists.

(Ed Stockly) #3

I should not ignore good advice from smart people.

(Shane Stanley) #4

OTOH, Chris was a big fan of using System Events rather than the Finder. The deprecated Standard Additions commands like list folder, for example, suggest using System Events, not Finder. But sadly:

set partialPath to "Library:Scripts:"
tell application "System Events"
	set isPathGood to exists disk item partialPath --> true
end tell

(Christopher Stone) #5

Zoiks! Both of those are bad news.

Since I always use relative aliases or $HOME-posix-paths I’ve not seen that problem for long enough that I’d forgotten about it.

What’s the ASObjC alternative Shane?


(Shane Stanley) #6

The best solution is to avoid relative HFS paths – they’ve never been reliable for the reasons Ed quoted from the ASLG above.

At the application level, most stuff is being done with NSURLs and POSIX paths – doing it via HFS stuff is deprecated. And there’s one deprecated (C-based) function for doing the conversion. It’s that function that’s returning what you see here.

It may be that the Finder is still using Carbon HFS functions, or it may be building file references internally, and doing it’s own path parsing as part of that process.

I guess the way to do it in ASObjC would be to create an NSURL, and then compare the name of its volume with the first part of the HFS path. To be doubly sure, you’d probably need to ignore case (and that’s also going to depend on whether the volume supports case-sensitive paths).

If you can retrieve the volume, the NSURL exists, so a match of volume names is all you should need. Something like:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set partialPath to "Library:Scripts:"
set posixPath to POSIX path of partialPath
set partialPath to current application's NSString's stringWithString:partialPath
set hfsVolumeName to (partialPath's componentsSeparatedByString:":")'s firstObject()
set theURL to current application's |NSURL|'s fileURLWithPath:posixPath
set {theResult, theValue, theError} to theURL's getResourceValue:(reference) forKey:(current application's NSURLVolumeNameKey) |error|:(reference)
set isPathGood to theResult as boolean and (theValue's lowercaseString()'s isEqualToString:(hfsVolumeName's lowercaseString())) as boolean

That’s a lot more code than simply asking the Finder. Nonetheless, it’s also more than 10 times faster, so if you want to check a lot of paths, it might still be a better option.

But the fact that this whole issue comes up so rarely suggests it’s generally more an academic problem. I don’t think many people use relative HFS paths.

(Christopher Stone) #7

Hey Shane,

Not so. These are “relative-aliases” (my nomenclature):

alias ((path to startup disk as text) & "Applications:")
alias ((path to downloads folder as text) & "test file.txt")

I never, ever use unanchored partial paths.

If you’ve ever had a failure using this type of construct please let me know.

I confess that I really don’t often make aliases outside the startup drive – but my construct for that sort of thing is thus:

set nonStartUpDiskFilePath to "/Volumes/SanDisk Blade/test file 01.txt"
set myAlias to alias POSIX file nonStartUpDiskFilePath

It’s fast, and the alias coercion will throw an error if the disk isn’t mounted (or the item does not exist).


(Shane Stanley) #8

But they’re not what we’re talking about here – you’re effectively building paths at run time, and relevant to the startup disk. The issue Ed raised is a complete HFS path provided as a string when the named volume isn’t available.

Right – you’re avoiding the problem by not using an HFS path.

(Christopher Stone) #9

I did mention that I’d almost forgotten about this bug, and why.

The last time I got bit by it was some time around 2004-5, and was one of several reasons I started using systems to prevent that sort of thing from happening.


(Ed Stockly) #10

For what it’s worth, those are exactly the kinds of commands I am using in this script.

The script is syncing files to an archive. When the script gets an alias to a file that’s going to be synchronized, it removes the reference to the startup disc, and replaces is it with the path to the folder for those items.

“MacHD:Library:Scripts:My File.txt”

gets changed to:

“RemoteDirectory:Startup Drive Items:Library:Scripts:My File.txt”

and when it’s downloaded to a different machine it’s changed to:

“LocalStartupDrive:Startup Drive Items:Library:Scripts:My File.txt”

(With “LocalStartupDrive” being replaced with the name of the startup drive)

When downloading a file from the remote directory, if the script has to know if the file already exists. If it does exist, it checks modification dates and decides if it should be replaced. If it doesn’t exist, it duplicates it to that location.

So the error came in checking if the file exists.



Old timer AS people like me still use them when I am too lazy to do a lot of typing. Unfortunately I’m too lazy far to much. Of course when that function no longer works at all it will be a big pain to fix preexisting files. But why fix today what you can fix tomorrow. But in all seriousness someday it will just break all together, if they don’t remove it before that time.