Saturday, December 16, 2017

#1 2004-09-24 05:07:53 pm

dishusa
Member
Registered: 2002-12-15
Posts: 92

Exiting Scripts

I have a script I am writing that is called from filemaker pro. During the running of the script, I would like to put in a way to exit the script if an error occurs. I cannot find an "exit script" command so would I just make the script into a handler and then have error  conditionally tied to a "return" statement?

Offline

 

#2 2004-09-24 07:41:14 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4456

Re: Exiting Scripts

Applescript:

error number -128

... will stop a script from executing any further. It's the same "User canceled" error that's generated by the "Cancel" button in most dialogs.


NG

Offline

 

#3 2017-04-19 10:42:11 am

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

How does one trap & exit a script from within a nested handler? The "Return" or "error number -128" only exits the handler, and the (explicit or implicit) main run handler continues unwanted. (I don't want a quit/return because I might be running it in a script editor, or in an applet I may want to stop the main run handler and go straight to an idle handler. Here's where I wish there were a GoTo command in AppleScript!)

Operating System: Mac OS X (10.6.8)

Last edited by Schmye Bubbula (2017-04-19 11:56:12 am)

Offline

 

#4 2017-04-19 12:38:04 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4456

Re: Exiting Scripts

Schmye Bubbula wrote:

The "Return" or "error number -128" only exits the handler


error number -128 stops the execution of the script. However, since it's an error, it'll be caught if it's in a 'try' statement or in a handler governed by one:

Applescript:

on run
   try
       stopTheScript()
   end try
   say "I didn't stop."
end run

on stopTheScript()
   error number -128
end stopTheScript

In this case, you need an 'on error' section to look out for and pass this particular error:

Applescript:

on run
   try
       stopTheScript()
   on error number n
       if (n is -128) then error number -128
   end try
   say "I didn't stop."
end run

on stopTheScript()
   error number -128
end stopTheScript

Or, if you don't need to do anything special with any other errors:

Applescript:

on run
   try
       stopTheScript()
   on error number -128
       error number -128
   end try
   say "I didn't stop."
end run

on stopTheScript()
   error number -128
end stopTheScript


NG

Offline

 

#5 2017-04-19 07:39:05 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

^ Thanks, Nigel, for the instructive, detailed reply, above & beyond the call of duty! Thank you for your time!

I'm now straightened-out that error number -128 is "stronger" than resume. That would handle running things within a script editor, but I guess now what I'm really asking is whether there's a direct command or error handling routine to send the main run handler to the end of the script, skipping any interim lines, kind of like an EOF end of file, or "EOS end of script," so to speak, such that, e.g., an applet's idle handler could commence.

Offline

 

#6 2017-04-21 02:24:07 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4456

Re: Exiting Scripts

Hi Schmye.

return will take you out of a handler, returning the program flow to just after where the handler was called in the process which called it:

Applescript:

--on run
say "starting"
if (5 > 4) then return
say "continuing the run handler"
--end run

on idle
   say "idling"
   return 5
end idle

An alternative — and in some philosophies preferable — way would be to use the geography of the return condition:

Applescript:

--on run
say "starting"
if (5 ≤ 4) then
   say "continuing the run handler"
end if
--end run

on idle
   say "idling"
   return 5
end idle

If you want a handler to exit calmly following some error condition, put return in the on error statement:

Applescript:

say "calling the handler"
theHandler()
say "phew!"

on theHandler()
   try
       set fire to trousers
   on error
       say "oops"
       return
   end try
   say "false alarm"
end theHandler


NG

Offline

 

#7 2017-04-25 03:12:10 pm

DJ Bazzie Wazzie
Member
From:: the Netherlands
Registered: 2004-10-20
Posts: 2727
Website

Re: Exiting Scripts

Schmye Bubbula wrote:

I don't want a quit/return because I might be running it in a script editor, or in an applet I may want to stop the main run handler and go straight to an idle handler. Here's where I wish there were a GoTo command in AppleScript!


Use user defined handlers then which are called from the Idle handler too.

Applescript:

on run
   try
       -- do something
   on error
       doIdleStuff()
   end try
end run

on idle
   doIdleStuff()
end idle

on doIdleStuff()
   
end doIdleStuff

GoTo commands are considered harmful. Jumping back and forth in code is done using loops, if statements and routines who are all auto-indexed for you. It's how modern programming languages are designed. Going back to the labeled jumps in code is everything the programming language is designed not to do, therefore it's evil and should never be used in any circumstances. Besides that programming languages who support GoTo cannot jump from one routine into another, they can only jump within the same routine because it's how the stack works. So at the end even GoTo wouldn't help.

Last edited by DJ Bazzie Wazzie (2017-04-25 03:55:56 pm)

Offline

 

#8 2017-05-01 08:36:41 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

Thanks for all the help, guys! ... I'm still confused about one thing: I thought that error number -128 stops a script dead in its tracks. I was wanting to use that to make an applet quit upon a certain error in a handler (with a two-line quit/error number -128 combination). So why doesn't this concept script terminate with the error number -128 in the second_order_nested_handler() ?  Why does it work itself back up to the first_order_handler(), and only terminates there? (You never hear the beep in the run handler, so why does the error number -128 work in the 1st handler, but not in the 2nd nested handler? — they seem otherwise identical. See why I'm confused?)

Applescript:


on run
   first_order_handler()
   beep
end run


on first_order_handler()
   try
       second_order_nested_handler()
       
   on error errorMessage number errorNumber
       display dialog "Error " & errorNumber & return & return & ¬
           errorMessage buttons {"OK"} default button 1 ¬
           with title "(1st order handler)" with icon caution
       error number -128
   end try
end first_order_handler


on second_order_nested_handler()
   try
       error number -128
       
   on error errorMessage number errorNumber
       display dialog "Error " & errorNumber & return & return & ¬
           errorMessage buttons {"OK"} default button 1 ¬
           with title "(2nd order nested handler)" with icon caution
       error number -128
   end try
end second_order_nested_handler

AppleScript: 2.1.2
Operating System: Mac OS X (10.6.8)

Last edited by Schmye Bubbula (2017-05-01 08:38:36 pm)

Offline

 

#9 2017-05-02 01:31:50 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4456

Re: Exiting Scripts

Hi Schmye.

It's similar to the scripts in post #4 above. The call to the second-order handler's in the 'try' section of the first-order handler, so the error generated after the second-order dialog is caught by the first-order 'try'. This prevents the error from stopping the script and causes the first-order 'on error' to be executed, which displays its own dialog and then generates its own error number -128. There's no 'try' block "outside" the first-order one, so this last error succeeds in stopping the script.


NG

Offline

 

#10 2017-05-02 08:40:56 am

DJ Bazzie Wazzie
Member
From:: the Netherlands
Registered: 2004-10-20
Posts: 2727
Website

Re: Exiting Scripts

Schmye Bubbula wrote:

Why does it work itself back up to the first_order_handler(), and only terminates there?


As Nigel explained clearly how it works you might be interested in the technical part of it. error is not a termination but an exception like in other programming languages. error is actually another type of AppleEvent, like the run handler you can call error and define an error AppleEvent handler but it looks different in syntax and is called under different conditions. Like all handlers you can call other handlers within an handler, so stack order applies for an try-catch in AppleScript too.

Offline

 

#11 2017-05-03 05:10:34 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

I see. Finally I get it now. Thanks for your guys' patience with getting the concept through my thick skull!

Well, now that Error number -128 isn't any good to me in these circumstances, unless someone can come up with a more direct way of quitting an applet in a nested try situation (I now see that it wasn't nested handlers per se), I can't think of anything else within an error trap using AppleScript-proper than this vulgar, inelegant workaround:

Applescript:


try
   --
   --    
on error
   --
   try
       --
       -- [Some error condition requiring quitting this applet]
   on error
       -- [Error number -128 here would undesirably get trapped by the first try's error trap]
       tell application "System Events" to do shell script "kill -9 " & ¬
           unix id of process (short name of (info for (path to me))) & ¬
           " &> /dev/null &"
   end try
end try

But this only extricates me in an applet; I still don't know how to get out (just stop the script) when running in a script editor. (Which is more evil?—GoTo statements, or my extreme-prejudice workaround? wink )

sigh. I just wish that "quit" meant quit.... Oh, I suppose "quitting" the script as separate from quitting the applet somehow makes sense in the world of object-oriented programming (I guess the applet is some kind of "parent" to the script "child"), but to this GoTo-loving AppleScripter whose only prior programming experience was some 40 years ago with procedural languages such as BASIC, FØRTRAN, and ALGOL (hey, DEC Extended Compiled BASIC had optional line numbers that were mostly used as labels for GoTo commands tongue ), this annoying use of "quit" certainly isn't intuitive, but no doubt there's some scenario where it's advantageous. I confess I approach AppleScript still in a procedural programming manner. Why can't there be a no-recourse quit or halt or "EOF" (end of script) for the script itself?

Last edited by Schmye Bubbula (2017-05-04 11:41:02 am)

Offline

 

#12 2017-05-04 12:50:50 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 211

Re: Exiting Scripts

One method for dealing with stopping execution in arbitrarily deeply nested "try"'s:

Applescript:


set giveUp to false

try
   set someVariable to "one" as integer
on error
   try
       set anotherVariable to "two" as integer
   on error
       set giveUp to true
   end try
end try

if giveUp is true then return
display dialog "I'm still executing!"


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#13 2017-05-04 03:23:47 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

^ Yeah, thanks, I can see how that would work.... But by working it's way back up through all the nested tries and resuming where the blocks left off after an error occurred down the line, it could do things undesirable in them (the reason I brought this up in the first place), especially when the nested tries are occurring due to nested handlers — unless I put those "if giveUp is true…" checks strategically spread out all over my script. What a PITA to have to formulate elaborate workarounds crapping-up a script, for a language evidently without a simple "stop" command! (unless I'm missing something)

I just tried a script with one line: stop, and it gives a Result of "stop," but it apparently doesn't do anything, because if I add another line, it executes it.

Offline

 

#14 2017-05-04 03:48:35 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 4456

Re: Exiting Scripts

It's just a matter of design. Either don't nest 'try' statements, or don't exit scripts from within nested 'try' statements, or, if you do, make sure that the "User canceled." error gets passed back up the line:

Applescript:


on run
   first_order_handler()
   beep
end run


on first_order_handler()
   try
       second_order_nested_handler()
       
   on error errorMessage number errorNumber
       if (errorNumber is -128) then
           error number -128
       else
           display dialog "Error " & errorNumber & return & return & ¬
               errorMessage buttons {"OK"} default button 1 ¬
               with title "(1st order handler)" with icon caution
       end if
   end try
end first_order_handler


on second_order_nested_handler()
   try
       error number -128
       
   on error errorMessage number errorNumber
       if (errorNumber is -128) then
           error number -128
       else
           display dialog "Error " & errorNumber & return & return & ¬
               errorMessage buttons {"OK"} default button 1 ¬
               with title "(2nd order nested handler)" with icon caution
       end if
   end try
end second_order_nested_handler

Or maybe:

Applescript:


on run
   first_order_handler()
   beep
end run


on first_order_handler()
   try
       second_order_nested_handler()
       
   on error errorMessage number errorNumber
       handleError(errorMessage, errorNumber)
   end try
end first_order_handler


on second_order_nested_handler()
   try
       error number -128
       
   on error errorMessage number errorNumber
       handleError(errorMessage, errorNumber)
   end try
end second_order_nested_handler

on handleError(errorMessage, errorNumber)
   if (errorNumber is -128) then
       error number -128
   else
       display dialog "Error " & errorNumber & return & return & ¬
           errorMessage buttons {"OK"} default button 1 ¬
           with title "(2nd order nested handler)" with icon caution
   end if
end handleError


NG

Offline

 

#15 2017-05-04 04:01:37 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 211

Re: Exiting Scripts

I don't think this is as complicated as you're currently thinking it is.

I think error -128 stops a script in all instances except for being inside a "try" statement, and the only purpose of a "try" statement is to catch potential errors and maintain the script's ability to execute regardless of what happens inside... so it's natural that it keeps going when there's an error... that is the sole point of the construct.

It would probably help us out to see your actual code.

"Error -128" stops a script dead even if it's called inside a handler:

Applescript:

doSomething()
display dialog "I'm still executing!"

on doSomething()
   error number -128
end doSomething

It just doesn't stop a script dead when called inside a "try." Because the whole purpose of the "try" is to keep the script going.

And even your more recent example doesn't actually require my method, you can go as deep as you want in "try's" and whenever you get to the bottom, you can still stop the whole thing with an "error number -128" as long as the first condition of the "try" on each step failed so the script got there, and you want any other code within the "on error" handlers to execute.

Applescript:

try
   set someVariable to "one" as integer
on error
   try
       set anotherVariable to "two" as integer
   on error
       error number -128
   end try
end try

display dialog "I'm still executing!"

Just out of curiosity, out of BASIC, FØRTRAN, and ALGOL, did any of them actually have error handling?

I'm not saying you don't have a good usage case for this situation you've presented, but I'm having trouble picturing it... if you want the script to stop for certain when certain criteria are met, why is that taking place as the error handler on a "try?" Why not just use an "if" statement? And why all functions calling functions within error handlers? The people reading this have collectively got 100's of thousands if not millions of lines of AS behind them, but from my experience, I'm guessing we haven't had problems with these particular issues. Don't get me wrong, Applescript's got its confusing parts to wrestle with. Just having the stop command be "error number -128" is pretty non-intuitive. But if you're used to much older languages, I think your best bet would be to give us a bigger chunk of your intended program logic and let us tell you how we'd structure that in AS. My hunch is that it's not going to be that bad.

It's hard to say without knowing the actual goal.

Last edited by t.spoon (2017-05-04 04:13:37 pm)


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#16 2017-05-04 04:16:10 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

Yeah, I think the key, as Nigel said, is to make sure that the "User canceled" error gets passed back up the line. That's the least "urban sprawl" approach, and I can make that work.

Offline

 

#17 2017-05-04 09:28:55 pm

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

Oh, I didn't answer your questions: Yes, all three procedural programming languages had robust error handling. And my usage case was a handler that called the macOS Keychain for a password, and if it errored-out from the password not already being there, it would call another, nested handler that gives the user the ability to add the password to Keychain, then return to the first handler, which would then recursively call itself to fetch the password again. My problem was, both handlers have their own dialogs for errors such as wrong password, canceling the dialog, etc., and the passing back up the chain a "User canceled" error would lead to double error messages and resumption of the first handler, when a certain dialog in the nested handler had said it would now just quit the applet. Now that I know to be sure to pass the error back up the line, that should fix it if I can get it all sorted out in my mind — or I can just stick with my "terminate with extreme prejudice" workaround, because I was quitting the applet at that point, anyway, which I've already gotten to work.

Thanks again for both of you all's help! (That's southern for, "Thanks for both of your help." cool )

Offline

 

#18 2017-05-05 01:54:52 pm

t.spoon
Member
From:: BFE, Massachusetts
Registered: 2013-01-13
Posts: 211

Re: Exiting Scripts

In case it's helpful to you, I'd do something like this.

I don't have any "try" statements in here. Not that a "Try" statement is something to be avoided, I just didn't need any in this situation.

Of course my password "validation" is a total joke, but I saw no reason to bother with any serious logic for that since this was just about program flow.

IMHO, if you want password validation, then this would be a great opportunity to use ASObjC so you can check the password and provide feedback live inside a dialog, instead of in a repeat loop.

Oh, and obviously, if anyone's using "!!PasswordNotFound!!" for their password, then this script will perform very poorly.

Applescript:

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


set passwordName to "Jim"
set retreivedPassword to getPassword(passwordName)


on getPassword(passwordName)
   set thePassword to "!!PasswordNotFound!!"
   repeat
       set thePassword to do shell script "security find-generic-password -wl '" & passwordName & "' || echo '!!PasswordNotFound!!'"
       if thePassword ≠ "!!PasswordNotFound!!" then
           exit repeat
       else
           my setPassword(passwordName)
       end if
   end repeat
   return thePassword
end getPassword

on setPassword(passwordName)
   set newPassword to ""
   set repeatCount to 0
   repeat
       set checkResult to my passwordCheck(newPassword)
       if checkResult is true then
           exit repeat
       else
           if repeatCount > 0 then
               set initialText to "The last password you entered only had " & checkResult & " characters, but 6 is the minimum." & return
           else
               set initialText to "No password was found in your keychain for \"" & passwordName & "\"" & return
           end if
           set newPassword to the text returned of (display dialog initialText & "Please enter a new password with 6 characters or more, and the entry will be saved in your keychain." default answer "" buttons {"Cancel", "OK"} default button "OK")
           set repeatCount to repeatCount + 1
       end if
   end repeat
   do shell script "security add-generic-password -a " & quoted form of passwordName & " -w " & quoted form of newPassword & " -s " & quoted form of passwordName
end setPassword

on passwordCheck(aPassword)
   set charCount to (count of characters in aPassword)
   if charCount < 6 then
       return charCount
   else
       return true
   end if
end passwordCheck


Hackintosh built February, 2012 |  Mac OS Sierra
GIGABYTE GA-Z68X-UD3H-B3 | Core i5 2500k | 16 GB DDR3 | GIGABYTE Geforce 1050 TI 4GB
250 GB Samsung 850 EVO | 4 TB RAID
Dell Ultrasharp U3011 | Dell Ultrasharp 2007FPb

Offline

 

#19 2017-05-07 10:13:31 am

DJ Bazzie Wazzie
Member
From:: the Netherlands
Registered: 2004-10-20
Posts: 2727
Website

Re: Exiting Scripts

t.spoon wrote:

But if you're used to much older languages, I think your best bet would be to give us a bigger chunk of your intended program logic and let us tell you how we'd structure that in AS.


I think initially Schmye was looking for an exit, syscall or signal command, I think that was his goal. Because in AppleScript everything is an AppleEvent, including quit and error handlers, there is no such similar command. Therefore an error is not actually an error but an AppleEvent like any other, only of an certain type. Quitting is not exiting but an system wide used AppleEvent to call another function to eventually gently stops itself (as all applications does when pressing cmd+q or choose quit from the menu).

If you look at AppleScript as an RPC-language it makes it all very clear why it behaves this way and why it behaves so different from all other programming languages. As a rule of thumb, when you're in AppleScript you have to forget every other programming language that exists because it will not clarify anything but leaves you confused most of the time.

Offline

 

#20 2017-05-07 10:21:08 am

Schmye Bubbula
Member
Registered: 2003-11-23
Posts: 113

Re: Exiting Scripts

^ Yeah, DJ Bazzie Wazzie, that's what I was trying to say earlier: As someone who's never programmed in a modern object-oriented language, I freely admit that by using AppleScript, old habits die hard, and I'm often trying to pound a procedural square peg through an object-oriented round hole. big_smile

And thanks, t.spoon, for the no-try routine that avoids having to follow errors up the line of nested handlers.

Last edited by Schmye Bubbula (2017-05-07 10:33:45 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)