AppleScript is an easily approachable scripting language built into OS X. However, as with any programming language, performing complex tasks with AppleScript can be difficult and requires thorough knowledge of advanced programming techniques.
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.
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.
1 2 3 4 5 6 7 8 | --Declare Variables set x to 5 set y to 78 --Run if Statement if x < y then return "yes" end if |
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.
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.
1 2 3 4 5 6 7 8 9 10 | --Declare Variables set x to 78 set y to 5 --Run if Statement if x < y then return "yes" else return "no" end if |
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.”
1 2 3 4 5 6 7 8 9 10 11 12 | --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 |
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.
1 2 3 4 5 6 7 | set theBoolean to false if theBoolean = true then return "It's true!" else return "That's just not true" end if |
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:
1 | display dialog "Greetings!" |
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:
1 | display dialog "How are you?" buttons {"Great", "Horrible", "None of your business!"} default button 3 |
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. 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | --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 |
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.
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.
1 2 3 4 5 6 | --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 |
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.
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. 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | --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 |
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.
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.
Operators
In the same way that variables store a lot of information in a small snippet of code, operators (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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | --Define Operator on additionOperator(theVariable) set x to 5 set y to 5 set z to x + y + theVariable display dialog "10 + " & theVariable & " = " & z end additionOperator --Run Operator additionOperator(8) --Run Operator Again set theNumber to 145 additionOperator(theNumber) |
The syntax for defining an operator is: on operatorName(variable), followed by the commands to execute, followed by “end operatorName.”
The variable in the parentheses (theVariable) is the part that we must define every time we run the operator. The first section of code by itself will do nothing because we haven’t yet run the operator, only defined it.
Notice when we run the operator we type the operator name followed by a number in parentheses. The operator will now take this number and insert it into any place we have typed “theVariable” into our operator 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 additionOperator(8) sets z to 8 and then adds 10 (5+5) and gives us the result of 18. When we run the operator 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 operator. Here we’ve set theNumber to 145 and then run the operator on theNumber. Note that any variables defined inside an operator don’t exist outside of the operator. So if you ended this script with “return z” you would get an error that tells you “z” is not defined. This means that you can technically use identical variable names for variables defined inside and outside of an operator. 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. 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:
1 2 3 4 5 | set theNumber to 5 repeat theNumber times display dialog "Isn't this annoying?" end repeat |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | --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 Operator 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 |
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. First we declare our variables, mostly boolean at this point. Then we create an operator (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.
First, 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). 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.
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, error handlers, operators 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 always, feel free to ask me any questions using the comment section below or directly through Twitter.
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!
Our Sponsors
Mac Apps

Really great tutorial! I’ve learnt heaps from this article, and I’ve always wanted to expand my knowledge in AppleScript. I feel like I’m starting to get the hang of it a little better.
Thanks for this, and I’d love to see more!
Geek stuff here.. Great tutorial :)
Joshua, thank you for this great tutorial! It’s awesome to get such a great series of introductions to AppleScript/Automator!
Keep it coming. ;)
Does anyone know if it’s possible using AppleScript to replicate GrabUp’s functionality? When I take a screenshot it takes it, uploads via FTP puts URL on clipboard then deletes? GrabUp’s not working on Snow Leopard and TinyGrab isn’t working for me either. I got Snapplr and it does it but doesn’t upload to custom FTP which is sorta important.
Excellent idea! It might be great for a future tutorial. In the mean time, here’s an Automator action that will upload a file to an FTP server. http://editkid.com/upload_to_ftp/
Also in Automator is an action to take a screenshot and save it in a specific location. You could setup a folder action on that location to automatically run any files that pop up in the folder with the upload action.
Now the real trick is getting the actual link to the pic to appear in your clipboard. This is where AppleScript comes in. You would have your path (all but the filename) set to a variable, then you would append the variable with the file name each time the script is run and copy the variable to the clipboard.
Voila! Your very own GrabUp utility… I will definitely have to try this!
Great Thinking Josh :-)
Josh, thanks for all this, Quote ‘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!’
So a question,
Can applescript solve my problem for me or am I asking too much of it?
At the end of the day I will be halfway through a project. Have a couple of word processor docs open, my diary program, a spreadsheet doc, and safari with a few tabs relating to what I’m doing.
->Can I write an applescript that will look at what’s open and record it so that the next time I want to work on that project I can activate the script and it will put everything back where it was?
( I know I could take a screen shot but that’s not what I’m asking, I want applescript to put it all there for me)
I know it’s a tall order and maybe it needs a dedicated app to do it, but it would save me a lot of digging.
Thanks in advance.
I’m not completely sure, but you can have applescript see what files are open, save the part to those files as a text document, and when you log in next, when you run the script, it will open the files…
The problem is that not all applications work with applescript. (But the main ones do.) To find out if the application works, go to the dictionary in Script Editor.
Thank you for the tutorial.
How can I filter files by extension selected in the following code:
tell application “Finder”
set these_items to the selection
end tell
thanks for the great tutorial. i’ve just noticed a little inconsistency with the final version of the number game. when run as it is shown here on the site, it actually tells you that you guessed it in one try less than it actually took. (ie if you get the number on your first try, it tells you you got it in 0 tries; if you get it on the second, it tells you you got it in 1 try; etc.) i’ve altered the last section slightly to reflect this. it also requires setting tryCount to 1 at the beginning instead of 0. this will now tell you the correct number of tries it takes you to guess the number:
–Count Number of Guesses
set tryCount to 1
…
…
…
–Is Result the Correct Answer?
if winningTest = true then
if theAnswer = randNum then
if tryCount = 1 then
dialogBox(“You guessed it in ” & tryCount & ” try!”)
else
dialogBox(“You guessed it in ” & tryCount & ” tries!”)
end if
else
dialogBox(“Try again.”)
set repeatTest to true
set tryCount to tryCount + 1
end if
end if
I write an applescript that will look at what’s open and record it so that the next time I want to work on that project I can activate the script