Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Advanced AppleScript Techniques

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

We've previously offered a basic introduction to AppleScript, and this article will cover a number of useful AppleScript tips and tricks to help you create some amazing advanced scripts.

This is part of a series of posts that revisits some of our readers’ favorite tutorials from the past that still contain awesome and relevant information that you might find useful. This post was originally published on September 24th, 2009.


First, Do Your Homework

This is the third article in my series on automation. Be sure to check out my Beginner's Guides to both AppleScript and Automator to get acquainted with scripting and automation in general.

In those articles I cover basic functions such as variables that I will not explain here to reduce redundancy. After you've familiarized yourself with basic AppleScript, you'll be ready to jump into the good stuff. Let's get started!


If and If, Else

"If" and "if, else" statements are used when you have a certain command or set of commands that you want the script to perform only if the stated requirements are met.

For instance, say you want the script to tell you if the value of two variables, x and y, is equal or different. You would use an "if" statement to tell the script how to react to each situation.

There are only three possibilities: x is greater than y, y is greater than x, or x = y. Let's start with a basic "if" statement and make it more complex as we go along.

[applescript]
--Declare Variables
set x to 5
set y to 78

--Run if Statement
if x < y then
return "yes"
end if
[/applescript]

Here I first declared two variables and assigned values to each. Then I told Script Editor to return "yes" if x is greater than y. Notice the structure of the "if" statement is much like a tell block. You must end every "if" statement with "end if" or your code will not compile.

You end every "if" statement with "end if" or your code will not compile.

The basic structure of the statement is as follows: If (a given statement) is true, then do the following. Be sure to include the statement to be tested and "then" on the same line as "if."

Then place your instructions on the next line(s) before ending the block. If you compile and run the statement above, Script Editor should return "yes," indicating that x is in fact less than y. If x were greater than y, nothing would happen because we haven't programmed for that contingency. Let's try something a little more complex.

[applescript]
--Declare Variables
set x to 78
set y to 5

--Run if Statement
if x < y then
return "yes"
else
return "no"
end if
[/applescript]

Here we've included an "else" statement that tells Script Editor what to do if the initial conditional statement is false. The structure is as follows: If (a given statement) is true, perform action a, otherwise, perform action b.

This is enough for many situations, but we still haven't created a contingency for our third situation: x = y. To accomplish this we'll use "else if."

[applescript]
--Declare Variables
set x to 5
set y to 5

--Run if Statement
if x < y then
return "x is less than y"
else if x > y then
return "x is greater than y"
else
return "x is equal to y"
end if
[/applescript]

Here we've allowed for all three different scenarios. Running this script should return "x is equal to y." Notice the last scenario only requires an "else" instead of an "else if." This is because if the first two statements are false, it must be the case that x = y (barring any input errors).


Booleans

Assigning a truth value to a variable is easy. Just set the variable to true or false.

[applescript]
set theBoolean to false

if theBoolean = true then
return "It's true!"
else
return "That's just not true"
end if
[/applescript]

For now just know that it's that easy. We'll see a more practical use in the final example.


Displaying a Dialog Box

AppleScript makes it super simple to display output to a user. Just type the following:

[applescript]
display dialog "Greetings!"
[/applescript]

This should produce a simple window displaying your greeting and two buttons: "Cancel" and "OK." It is also possible to customize those buttons with the following code:

[applescript]
display dialog "How are you?" buttons {"Great", "Horrible", "None of your business!"} default button 3
[/applescript]

There are three sections to this code. The first section displays a dialog box with the text "How are you?" The second section determines how many buttons the dialog will have and what they will say. In this case we have three buttons. Notice the set of buttons must be encased in brackets and each button encased in quotes.

Notice the set of buttons must be encased in brackets and each button encased in quotes.

The resulting dialog
The resulting dialog

Finally, the third section tells the dialog what the default button should be. Setting the default button to 3 highlights the third button when the dialog is shown.

Having a dialog with multiple buttons is great but it's no good unless you know how to use the input received from the user as a result. Let's take what we just learned about dialogs and combine it with an "if, else" statement to see how we can use dialogs to carry on a... well... dialogue.

[applescript]
--Create a dialog with 3 buttons
display dialog "How are you?" buttons {"Great", "Horrible", "None of your business!"} default button 1

--If user is great
if result = {button returned:"Great"} then
display dialog "Excellent, carry on good sir"

--If user is Horrible
else if result = {button returned:"Horrible"} then
display dialog "You need to cheer up!"

--If user is a jerk
else
display dialog "Excuse me pal!"
end if
[/applescript]

As you can see, the initial line of code is taken directly from the example above. The next portion uses an "if, else" statement to handle each button press. The syntax is essentially: If the user presses button x, then do action a, else if the user presses button y, then do action b, else do action c.

If the user presses button x, then do action a, else if the user presses button y, then do action b, else do action c.


Receiving Text Input From a User

Sometimes a simple button isn't enough. I frequently write scripts that require the user to input text. To accomplish this, we use a dialog box like above, with a slightly different syntax.

[applescript]
--Display Dialog and Get Input
display dialog "How are you?" default answer "Tell me how you feel"

--Get Answer & Return Comment
set theAnswer to (text returned of result)
display dialog "I'm glad you feel so " & theAnswer
[/applescript]

By putting a "default answer" into our code, we tell AppeScript that we want the user to input text in response. We then set a variable to the text returned by the user. Then we can use that variable anywhere we want to use the input.

Receiving Text Input From a User
Receiving Text Input From a User

Handling Errors: The Try Block

Letting users enter data is dangerous. If you are looking for a very specific answer or type of data you can be certain your users will screw it up and cause an error.

If you are looking for a very specific answer or type of data you can be certain your users will screw it up and cause an error.

For this reason, you need to filter what comes in from the user to make sure it's exactly the kind of input you want. For this, we'll use a try block and a couple of "if" statements.

[applescript]
--Display Dialog and Get Input
display dialog "Pick a number 1-10" default answer "Only Enter Numbers Less than 11!"

--Test For Invalid Characters
try
set theAnswer to (text returned of result) as number
on error
display dialog "Invalid Input"
return
end try

--Test for Correct Numbers
if theAnswer < 1 then
set theTest to 0
else if theAnswer < 11 then
set theTest to 1
else
set theTest to 0
end if

--Return Comments to user
if theTest = 0 then
display dialog "Invalid Input"
else
display dialog "You chose the number " & theAnswer
end if
[/applescript]

The code above is complicated so let's break it down. The first section simply displays a dialog and asks the user to pick a number. However, we only want to accept numbers one through ten. If anything else is entered, we want to tell the user the input was invalid.

The second section is where we test to see if any non-numbers were entered such as letters or symbols. A try block allows us to tell AppleScript to try to execute the code and see what happens.

A try block allows us to tell AppleScript to try to execute the code and see what happens.

Here we've told AppleScript to try to take the text returned by the user and turn it into a number. If there were no try block and we executed this command, it would throw an error and end the program if the user entered a letter or symbol.

However, the try block allows us to give AppleScript a special command if an error is thrown. In this case we display an "Invalid Input" dialog if an error is thrown. We then command the script to end by typing "return." Notice a try block must end with the "end try" command.

When programming, you must always consider every possible mistake that your users can make and create a contingency for it. Try running the code above and entering a few invalid characters. You can see that no matter what you enter, the script only accepts numbers 1-10.

When programming, you must always consider every possible mistake that your users can make and create a contingency for it.


Handlers

In the same way that variables store a lot of information in a small snippet of code, handlers (often called functions in other programming languages) are a great way to repeatedly execute a large number of commands with very little code.

By storing multiple commands in one snippet, you save yourself lots of programming and greatly simplify your code. Here's an example:

[applescript]
--Define Handler
on additionHandler(theVariable)
set x to 5
set y to 5
set z to x + y + theVariable
display dialog "10 + " & theVariable & " = " & z
end additionHandler

--Run Handler
additionHandler(8)

--Run Handler Again
set theNumber to 145
additionHandler(theNumber)
[/applescript]

The syntax for defining a handler is: on HandlerName(variable), followed by the commands to execute, followed by "end handlerName."

The variable in the parentheses (theVariable) is the part that we must define every time we run the handler. The first section of code by itself will do nothing because we haven't yet run the handler, only defined it.

Notice when we run the handler we type the handler name followed by a number in parentheses. The handler will now take this number and insert it into any place we have typed "theVariable" into our handler definition.

In this case, it will set the chosen variable to z and add it to x(5) and y(5) and display a dialog with the answer. So additionHandler(8) sets z to 8 and then adds 10 (5+5) and gives us the result of 18. When we run the handler again, the same code is executed on a different number.

I did this to show you that you can define a variable elsewhere and insert it into your handler. Here we've set theNumber to 145 and then run the handler on theNumber.

Note that any variables defined inside an handler don't exist outside of the handler. So if you ended this script with "return z" you would get an error that tells you that "z" is not defined.

Be sure to give all your variables descriptive and unique names.

This means that you can technically use identical variable names for variables defined inside and outside of an handler. However, this makes for messy and confusing code and should be avoided. Just be sure to give all your variables descriptive and unique names.


Repeat Blocks

It is often the case that you will find the need to create a step in your script that repeats a given number of times.

In AppleScript we accomplish loops with repeat blocks.

Many programming language call this a loop. In AppleScript we accomplish loops with repeat blocks. Repeat blocks are fairly simple and versatile, here's a simple example:

[applescript]
set theNumber to 5

repeat theNumber times
display dialog "Isn't this annoying?"
end repeat
[/applescript]

Here we've created a dialog box and set it to repeat five times in a row. This example, though useless, shows you how easy it is to create repeating steps.

However, you don't always know how many times you want a given step to repeat. It is often necessary to repeat a step or series of steps while a certain condition remains true. For these cases we use a "repeat while" block.

[applescript]
set theNumber to 1

repeat while (theNumber < 2)
display dialog "Play Again?" buttons {"Yes", "No"} default button 1
if result = {button returned:"Yes"} then
display dialog "Please insert more quarters!" buttons {"OK"} default button 1

else
display dialog "Goodbye!" default button 2
set theNumber to (theNumber + 1)
end if

end repeat
[/applescript]

Here we've setup the dialog that repeats while theNumber is less that 2. If the user says they want to play again, they are given a message to insert more quarters and the dialog repeats.

As long as the user keeps hitting yes, the dialog keeps repeating. When the user selects "No", we add one to theNumber, setting the value to two. The script sees that the truth requirement has become false and ceases repeating the action.


Putting It All Together

Rather than leave you with several bits of unconnected code, I thought it would be best to give one final example integrating everything we've learned above. Let's take the "pick a number" example above and flesh it out into a fully working script.

[applescript]
--Set Random Number
set randomNumber to random number from 1 to 10

--Boolean to Test if Script Should be Repeated
set repeatTest to true

--If Result Is a Number, Change to True and See if the Number is Between 1 and 10
set testNumbers to false

--If Result Passes All Previous Tests, is it Correct?
set winningTest to false

--Count Number of Guesses
set tryCount to 0

--Generic Dialog Handler
on dialogBox(theMessage)
display dialog theMessage
end dialogBox

--Repeat if Any Tests Are Failed
repeat while (repeatTest = true)
--Display Dialog & Get Result
display dialog "Choose a number 1-10" default answer "Enter Only Numbers 1-10" default button 2

set theAnswer to (text returned of result)

--Is Result a Number?
try
set theAnswer to theAnswer as number
set testNumbers to true
on error
dialogBox("Invalid Input")
end try

--Is Result Between 1 and 10?
if (testNumbers = true) then
--Test for Correct Numbers
if theAnswer < 1 then
dialogBox("Invalid Input")
else if theAnswer < 11 then
set repeatTest to false
set winningTest to true
else
dialogBox("Invalid Input")
end if
end if

--Is Result the Correct Answer?
if winningTest = true then
if theAnswer = randomNumber then
dialogBox("You Guessed it in " & tryCount & " tries!")
else
dialogBox("Try Again!")
set repeatTest to true
set tryCount to tryCount + 1
end if
end if

end repeat
[/applescript]

At first glance this script may seem intimidating. However, if you've gone through all of the examples above, it should all make perfect sense.

Step 1: Declare Your Variables

First, we declare our variables, mostly boolean at this point. Then we create a handler (dialogBox) to display our various dialogs throughout the script. The user is then asked to pick a number between 1 and 10. The answer is then run through three separate tests.

Step 2: Check the Input

Next, we test to see if the input contains letters or symbols. Then we test to see if the number returned by the user is in the acceptable range (1-10).

Step 3: Does the Input Match the Random Number?

Finally, we test to see if the user's guess matches the random number generated by the script.

Using booleans and if statements the script is structured so that each consecutive test is only run if the input passes the previous test. If any test returns false, the repeat block begins again and the following actions are not run.

Nesting

Notice that it's actually possible to nest if statements within if statements. This is true of repeat blocks and tell blocks as well. Be careful though of using nested statements excessively. One or two layers deep isn't bad but anything beyond that just gets messy and hard to follow.

Running this script should let you choose a number and keep guessing until you get it right. Play with it a few times and see how many guesses it takes you to get it right!


Conclusion

This article has walked you through using if statements, booleans, dialog boxes, user input, handlers, error handlers and repeat blocks.

You should now be equipped to create some seriously fancy scripts that will automate the toughest of workflows. Just bookmark this page and use it as a cheat sheet for all your future scripts.

As mentioned above, this is the third installment in my series on automation. Your feedback is very important in deciding what I write about so let me know if you'd like me to keep them coming. If the demand is great enough, I'll gladly write more!

Advertisement