AppleScript not opening file [SOLVED]

If I have this last action set to:

open file "Macintosh HD:Users:dannywyatt:My Files:Focus:Plan.numbers"

it opens the file as it should.

  • Now the way I have it set up using a variable, doesn't work.
  • It also doesn't work if I use the "normal" path like this:
    "/Users/dannywyatt/My Files/Focus/Plan.numbers" (instead of using a variable and instead of using the path with : as a separator).

Any tips on why these 2 options don't work?
I would guess that the 2nd option is probably because of that POSIX "thing", that I still haven't learned, but maybe it's something else...?

Daily Reminder.kmmacros (23 KB)

Keyboard Maestro Export

Bang on. It's easiest to pass the full path in to the AS, so the ~ needs to be expanded, then you need to get in into a file reference that open understands with something like

open POSIX file finalPath

Something like this should do it -- I've filtered to your original Local__finalPath variable in case you want to use the abbreviated form elsewhere, but you could Filter to source then change your AS to get variable "Local__pathToPlan".

Daily Reminder v2.kmmacros (21.8 KB)

You can do the path expansion in the AS instead, but it's probably easier this way!

1 Like

Thank you.
Unfortunately, this doesn't work.
The only way to make it work is when I use the version with the : as separator. That's why I was adding that shell action and all that. So weird...

Also, I noticed that both the Standardize Path and Expand Tilde give the exact same result. Is it supposed to be this way?

OK, there's two (at least!) problems. There's a problem running the AS "asynchronously". And the path conversion that was working on my test machine isn't working on this one -- and when I do it properly here it falls foul of the "error -128" osascript bug, discussed elsewhere on this Forum, because of going through the Finder. But since you seem to be using Numbers anyway...

This seems to fix everything -- I can't see any reason for the async execution so turned off that option. Give it a go:

Daily Reminder v3.kmmacros (21.8 KB)



It's working now. Thanks!
It wasn't working at first, but the issue was that my original macro would open Numbers right away, but this one doesn't, so I thought it wasn't working at all. Every time I would run the macro inside KM, it would just keep KM as my front application and I wouldn't even check Numbers. My bad...

I changed the script to this:

set kmInst to system attribute "KMINSTANCE"

tell application "Keyboard Maestro Engine" to set finalPath to getvariable "Local__finalPath" instance kmInst

display dialog ¬
	"" & finalPath & " - Check daily Plan" with icon note buttons {"Cancel", "Open Plan"} default button "Open Plan"
tell application "Numbers"
	open POSIX file finalPath
end tell

The reason I was using Async is because I don't want the Engine to be running for long. Not sure if that is an issue, but when the macro runs, I'm not always around, so if the macro runs at 6am and I only check it at 9am, the Engine will be running all that time and I'm not sure if that could eventually cause any issues with the CPU or anything?

So, is there a difference between using Standardize Path and Expand Tilde in the filters? It seems to get the same result.
I checked the Wiki page, but unfortunately I feel that more often than not, those pages lack examples to illustrate what's being said, so it isn't clear what Standardize Path does.

That'll be because AS is putting up a "blocking" dialog -- you could include giving up after... so the dialog self-cancels, but I suspect you want it there when you finally get to your machine.

Since you don't care if the AS completes before the macro finishes, how about trying a short time out on the AS action, set to "don't abort" and "don't notify". Not tested, but I assume the AS will remain running but paused waiting on the dialog response while the macro runs to completion and exits.

Both are applications of standard "methods" provided by NSString in Apple's Foundation classes.

stringByStandardizingPath | Apple Developer Documentation

stringByExpandingTildeInPath | Apple Developer Documentation

You won't usually notice a difference, and the former actually calls the latter, but additionally does a little more tidying up, of a kind that will seldom affect you much.

If you start with the slightly redundant


I think you will find that both expand the tilde, but only one tidies away the unneeded trailing /.

In AppleScript terms you would see the difference with:

Expand disclosure triangle to view AppleScript source
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on run
	set rawPath to "~/Desktop/."
	set fps to {tildeExpandedInPath(rawPath), filePathStandardized(rawPath)}
	set my text item delimiters to linefeed
	return fps as text
end run

-- filePath :: String -> FilePath
on tildeExpandedInPath(s)
	((current application's ¬
		NSString's stringWithString:s)'s ¬
		stringByExpandingTildeInPath()) as string
end tildeExpandedInPath

-- filePathStandardized :: String -> FilePath
on filePathStandardized(s)
	((current application's ¬
		NSString's stringWithString:s)'s ¬
		stringByStandardizingPath()) as string
end filePathStandardized

Yes, I want it to be there when I get to my computer, but I didn't want the engine to keep running. If this is not an issue, the engine running for like 3 hours or more, then that's ok. I usually check it around 6am anyway. At least, most of the time. Would that be an issue or should I not care?
And why is it working with async when I'm using my first version with the path instead of the variable, but not with the variable?

Ok this is probably the shortest and easiest way to understand it. It's a small detail, the removal of the /. at the end, but I can see how that could be useful in certain macros.

I will have to check those links to see if I can understand their content.

Basically it seems that Expand Tilde will only check the beginning of the path and if it starts with ~ or ~user it will replace that, but leaves everything else the same. Standardize Path will do more stuff.

Thank you so much for clarifying this, for the links, and for the code. I tested it and I can see how they both work. Saved those links for future reference and read.

1 Like

Sorry, I should have thought of that -- going direct to Numbers means it doesn't come to frontmost. If you want it to then add an activate just before opening the file:

tell application "Numbers"
	open POSIX file finalPath
end tell

There's certainly something hinky with async AS actions and local variables -- I'll run some more tests when I get the time. But. if you insist on async, you could use a global variable instead -- a quick test suggests they work fine.

OK, so setting a timeout on the AS action doesn't work -- the AS gets cancelled (which makes sense when I think about it!).

But a macro that is paused waiting on a dialog (rather than one eg constantly scanning the screen waiting for something) uses very little in the way of resources, especially compared to all the things your Mac is doing in the background anyway. You may even be more using more by needlessly spawning an AppleScript...

I think I'd shortcut the whole process and just go with:

...though you'll need to change the "Alert" timeout from its default 3 minutes. Even the variable-setting action seems a bit indulgent in such a short macro, I'd probably just include the path in the "Open" action.

The only thing you're really missing out on is the change of icon in the dialog...

This may be a more interesting and useful test-case for standardize vs just expand:


The relative reference (two dots) to the the parent directory
is automatically resolved to an absolute reference
to the parent directory itself.

In my testing years ago for something else I was doing, I found I had to use global variables (not even instance worked) if the AppleScript was running asynchronously. Using anything other than global meant the variables never got to the script.

I suspect that this is because an asynchronous AppleScript gets a fresh environment from KM that would only include globals, because anything else isn't there because nothing's been running in that environment? Only @peternlewis could explain for sure (and in much more precise language, I'm sure :))


What's confusing me is that the async AS gets less visibility on the local variables of its parent macro than an external AS does. Demo:

Local Async AS.kmmacros (3.4 KB)


If you get the following ready in your favourite script editor:

set theInst to "pasteItHere"

tell application "Keyboard Maestro Engine"
	set theVar to getvariable "Local_var1" instance theInst
end tell

display dialog "theVar is: " & theVar

...then run the macro, copy the instance ID from the dialog, paste it into the first line of the script to replace pasteItHere, then run the script before the macro finishes:

  1. The script editor AS will display the value of the KM variable Local_var1
  2. The macro's AS won't display the value of Local_var1

So yes, if you want to use an async AS with values set by the parent macro, use a global variable (or write then read a temp file).

1 Like

I have it set to open Numbers after opening the file which is also ok. Both work. :slight_smile:

Yes, I can do that and then delete the variable at the end of the script. Thanks for the tip.

Regarding the async, besides the CPU thing (which you already mentioned that it doesn't seem to be an issue), I want to make sure that the dialog is there, even if there's an issue with the Engine (if it stops working/quits, etc).

I will try the global variable now and see how it goes. Thanks again for your help!

I just tested it as async and with global variable, and unfortunately, for some weird reason, it doesn't open the file. It opens Numbers (I changed the "activate" to happen before the "open"), but it doesn't open the file. As soon as I change it back to Ignore Results, it opens the file.

But I decided to try another approach and everything is working now :wink:
It's just an extra action, so no big deal.

Daily Reminder.kmmacros (23 KB)

Keyboard Maestro Export