Avoid warning when doing shell script in the middle of a tell-statement?

If you do something like this:


tell application "Safari"
-- code
do shell script "echo hello world"
-- more code
end tell

you get a warning/error message

Error: a privilege violation occurred (errAEPrivilegeError:-10004)

What are some good “design patterns” to avoid this, without having to end the tell block (which can be multiple levels deep tell tab 1 of document 1 of window 1 etc)?

It works for me too, but I get a warning/error when I do it.

I see what you mean, and the following may explain the reason for the warning message:

For security reasons, most scripting addition commands now return a “privilege violation” error when sent between application processes. In order to preserve compatibility with existing scripts, AppleScript redirects most of these commands to the current application, that is, the process running the script.

The options would appear to be to:

  • ignore the warning message if the command works;
  • move the command out of the tell statement; or
  • put the command in a handler and call it from within the tell statement (preceded by the my keyword).

A fourth option, which seems a bit clumsy but avoids the warning message, is:

tell application "Safari"
	-- code
	tell current application to (do shell script "echo hello")
	-- more code
end tell

If I run your code in Script Editor, I see this in the “Replies” tab:

tell application "Safari"
	do shell script "echo hello world"
		--> error number -1708
	«event ascrgdut»
		--> error number -1708
	do shell script "echo hello world"
		--> error number -10004
end tell
tell current application
	do shell script "echo hello world"
		--> "hello world"
end tell
Ergebnis:
"hello world"

Error -10004 is the privilege violation, BTW. Apparently, ScriptEditor tries to run do shell script _three_times (each of them failing with an error) before it wraps the call in a tell current application block, which finally makes it succeed.

And that’s what I know from JXA, too: doShellScript has to be called on the current application object like so

const ca = Application.currentApplication();
ca.includeStandardAdditions = true;
ca.doShellScript(`echo "Hello World"`);

There, this doesn’t cause any trouble because the method is called on an object that is separate from the rest of the application objects: No nested tell blocks or so.

For most situations, what’s wrong with tell me?

tell application "Safari"
	-- code
	tell me to do shell script "echo hello world"
	-- more code
end tell

From Technical Note 2065:

Does it make a difference which application I tell to do shell script?

For the most part, no. For security reasons, do shell script always runs as a child of the process running the script, regardless of what application is the current “tell” target. However, AppleScript must perform some extra work to redirect do shell script commands sent to other applications, so for optimal results always put do shell script calls outside of any tell block, or use tell me.

As an aside, all of the formatting in the above note was added automatically during the copy/paste from the source document. I haven’t seen that before.

1 Like

I did some quick testing and “tell me” and “tell current application” both work to avoid the privilege violation error. If one of these is not used, what the documentation terms a “double-send” is done, and this causes a delay of about one millisecond. That’s much too small to notice, but good coding would seem to require that tell me or tell current application be used, or that the scripting addition command be moved outside the tell statement.

This appears to apply to many Scripting Addition commands and current date is just one example. The following is returned by Script Editor:

tell application "Finder"
	current date --> error number -10004
end tell
tell current application
	current date --> date "Sunday, July 9, 2023 at 6:06:41 PM"
end tell

As I understand it, me, as in tell me is the current script. Current application is the application that owns the script, e.g. Script Editor, or the script application.

The former seems more local to the do shell script command — at least to me. TN2065 suggests that under the hood, applescript will prevent applications from running the command.

The AppleScript Release Notes linked above suggest using “tell current application” and this is with any Scripting Additions command. And, current application is defined as the “process running the script”, which could vary depending on how the script is saved and run. So, I don’t know if one is better than the other or if it really matters.

I generally try to keep Scripting Addition commands out of tell statements, and that seems a safe approach.

You’re right, it’s a little vague. FWIW, I think that both the ASLG and the TN2065 have been updated since the release notes for 10.6 were published and go into a little —tiny bit— more depth.

What is the syntax if you want to achieve that in a line like this:

log "Loops: " & noLoops & " - " & (time string of (current date))

The following are the alternatives recommended by Apple. I deleted noLoops because it wasn’t defined, and I used Finder just to demonstrate but it could be Safari or something else.

--alternative 1
tell application "Finder"
	tell current application to set dateString to date string of (current date) -- or use tell me
	log "Loops: - " & dateString
end tell

-- alternative 2
set dateString to date string of (current date)
tell application "Finder"
	log "Loops: - " & dateString
end tell

BTW, this is obvious but the line will run fine as written if it’s not in a tell statement:

set noLoops to "some text"
log "Loops: " & noLoops & " - " & (time string of (current date))

It is in a tell-statement. How can I keep it on one line without getting a warning/error?

The following works on my Ventura computer and does not return an error message:

tell application "Finder"
	log "Loops: - " & date string of current application's (current date)
end tell

When I tried your suggestion within a Safari tell block:

log "Loops: - " & (time string of current application's (current date))
log "Loops: - " & (time string of my (current date))

I get this error message

(*Safari - errMsg: Can’t make document "MacScripter" of application "Safari" into the expected type.*)

This is within this structure

on run {}
	tell application "Safari"
		try
			tell document 1 to repeat
				log "Loops: - " & (time string of my (current date))

What gives?

Why are you telling a document to repeat?

Because the site the document displays continuously change. Does the repeat cause problems with the solution to the scope problem?

No idea. It’s peculiar though.

Generally, when you tell x to (as opposed to creating a regular tell block) you are having it do a single thing, e.g. tell document 1 to close. That doesn’t seem to the case here.


On the previous matter of current date, again… why not just use my?

tell application "Finder"
	set noLoops to "some text"
	log "Loops: " & noLoops & " - " & (time string of my (current date))
end tell

That said, I don’t think that the loop log needs to be in a tell block at all.

Because, as I mentioned above, it returns an error/the same error.

My suggestion works fine in my testing, and the issue appears to be with your script. I don’t know what you are attempting to do but the following demonstrates that “time string of my (current date)” works as expected (it takes 15 seconds to run):

set theURL to "https://www.macscripter.net"

tell application "Safari"
	activate
	repeat 3 times
		open location theURL
		log "Refreshed: " & (time string of my (current date))
		delay 5
	end repeat
end tell

I see a similar error in Safari 14 on my Mojave system. It must be something to do with the Safari document not understanding the ‘log’ command, but, interestingly, while this immediately errors saying the document can’t be made into the required type …

--on run {}
tell application "Safari"
	-- try	
	tell document 1 to repeat
		log "Loops: - " & (time string of my (current date))
	end repeat
	-- end try
end tell
--end run

… these two variants both keep logging as expected:

--on run {}
tell application "Safari"
	-- try	
	tell document 1 to repeat
		log "Loops: - " & (time string of (current date)) -- No 'my'.
	end repeat
	-- end try
end tell
--end run
--on run {}
tell application "Safari"
	-- try	
	tell document 1 to repeat
		tell me to log "Loops: - " & (time string of (current date)) -- tell 'me' to do the whole line.
	end repeat
	-- end try
end tell
--end run