Save Time and Effort with AppleScript Repeat Loops

Continuing along in our ongoing series of AppleScript articles, today we're going to learn about the power of repeat loops, which can save you tons of effort by automating repeating tasks and groups of commands. After you learn to use repeats, you'll be able to significantly cut down on the amount of work it takes to automate tasks, which translates to faster, easier coding and higher productivity.

More Great AppleScript Tutorials

Before we get started with learning about repeat loops, be sure to check out some of our previous AppleScript tutorials.

Repeat the Sounding Joy

If you did it right the first time, isn’t once enough?

If you've ever done any programming or scripting before, then you know that loops are absolutely critical to accomplishing nearly any significant feat. However, if you're new to the idea of programming, you might be wondering why the heck you'd ever want to repeat something. If you did it right the first time, isn't once enough?

The answer of course lies in the fact that we frequently work with massive amounts of data. If you have five hundred images in a folder and want to do something to every one of them, then you can either type out the same command five hundred times, targeting it at a different file each time, or use a repeat loop and save your sanity.

The Structure of a Repeat Loop

If you read my previous article on conditional statements, then the structure of a repeat loop should be familiar. As with many other AppleScript constructs, the repeat loop forms a block of code with a start and end.

[applescript]
repeat 3 times
--commands to repeat
end repeat
[/applescript]

As you can see, the initial line begins with "repeat" and then outlines the terms of the repeat. The middle section is where all of the various commands to be repeated will be placed and the last line informs the compiler that this is where the loop ends.

The structure of a repeat loop.

The code example above is pretty straightforward thanks to AppleScript's high level of readability. Anything within this repeat block will be repeated three times, then the script will move on (unless there's a termination action in the repeat).

One thing that you're going to want to keep in mind is that your code needs to be written in such a way that repeating it actually does something useful. It's often the case that a given section of code will be the same whether you run it once or a thousand times. It's up to you to mold it in such a way that the repeat causes progress. We'll see how to do this as we learn about the different types of repeats that are available.

Types of Repeat Loops

In a previous article, we talked about how you can vary your if statements considerably through different combinations of if, else and else if. Repeat loops can achieve an even higher level of variation because there are actually lots of different types of repeat loops in AppleScript. Let's go over each and how it works.

One Infinite Loop

The first type of repeat is an infinite loop. This occurs if we simply use a repeat block with no modifiers of any kind.

If you run this script, it will go forever, displaying a dialog every time it executes. There are very few practical use cases where you would want an infinite repeat so, as a general rule, make sure that you always add extra code to that repeat statement that governs the duration or count of the repeat.

Repeat a Specific Number of Times

The next type of repeat was shown in our first code example above. This is where we specifically state how many times we want a chunk of code to repeat. Here's an example:

In this code, we call up a dialog box containing a simple message. The repeat block is set to execute this twice, so as soon as the user clicks one of the buttons in the first dialog, another will pop up in its place.

The same window will pop up twice.

As I mentioned above, repeating the exact same thing twice like this isn't typically that helpful. What we need to do instead is figure out a way to vary the output. Let's see if we can get the repeat block to execute twice, but display a different message each time.

[applescript]
set theMessages to {"Hello there!", "Let's learn about AppleScript!"}
set x to 1

This might seem a little confusing, but don't worry, it's really simple. We start off by declaring a list. A list allows you to wrap multiple pieces of data up into a single variable. Here we've taken two different strings and tossed them into "theMessages". We can access each list item by its number. So "Hello There!" is "item 1 of theMessages" and "Let's learn about AppleScript!" is "item 2 of theMessages".

Next, we take advantage of an extremely important construct: a counter. This is the secret to making a repeat do something different each time it runs. For this example, we set x to equal 1, then we incremented x at the end of the repeat. This way, every time the repeat runs, the value of x increases by one.

The effect that this has on our code is profound. The first time the repeat runs, x is equal to 1, so item 1 of our list is accessed and our first message is displayed in the dialog. Then the value of x in increased to two, which causes the second message to be displayed the second time through the repeat.

This time, two different messages are displayed.

Tip: Notice that we have to use a numeral (2) in a specific repeat, spelling out to repeat something "two times" won't work.

Repeat With Number Range

If you're looking to cycle through something via an incrementing variable, there's a more succinct way to go about it than what we saw in our previous example. Using the repeat with construct, we set up a counter that's built right into our loop and can be accessed from the code within. Let's see what this looks like by tweaking the previous code example:

[applescript]
set theMessages to {"Hello there!", "How are you?", "Let's learn about AppleScript!"}

repeat with n from 1 to 3
display dialog (item n of theMessages)
end repeat
[/applescript]

As you can see, this time around we have three messages to cycle through. Notice that our code has actually been simplified though. We've stripped out the creation and incrementing of a variable and instead told the repeat block to "repeat with n from 1 to 3".

What this does is create a variable n, then increment it by one each time the block repeats. The starting and finishing numbers are determined by the "from 1 to 3" part. So the first time this is run, n will equal 1, then 2 the next time, and finally 3 the last time.

Quick and easy access to the counting variable makes repeat with an extremely useful repeat structure. You'll find yourself using this frequently.

Repeat With List

There's another form of a repeat with block that ditches the numbers and instead is specifically structured to cycle through the items in a list. This is exactly what we've been trying to achieve, so this is perfect for our example. Here's our repeat block, simplified yet again.

[applescript]
set theMessages to {"Hello there!", "How are you?", "Let's learn about AppleScript!"}

This time, we tell AppleScript to repeat the code block with the message variable in the list theMessages. What this means is that the code block will run once for every item in our list. So in this case, it'll run three times. Each time it runs, the contents of the current list item is placed into our message variable, which we access in our display dialog command later.

Repeat While

The next repeat loop that you can leverage in your code is repeat while. This one is easy to understand but still super powerful. Basically, it allows you to repeat a given block of code while a given boolean is true. Here's a simple example that doesn't do much, but illustrates the point:

[applescript]
set x to true
set y to 0

repeat while x
if y > 10 then
set x to false
else
set y to y + 1
end if
end repeat
[/applescript]

In this script, the block of code will repeat infinitely as long as x is true. However, inside the repeat, we set x to false if y is greater than 10, and increase it otherwise. This means that the code can only repeat a few times because eventually y is going to get to 10 and then the repeat will stop.

Note that I could've used this structure as well:

[applescript]
repeat while x is true
--code to repeat
end repeat
[/applescript]

This code works just fine, but the "is true" isn't necessary. The reason for this gets at the very core of just what a boolean is and what it does. The variable x in our example equals true, the two are one and the same.

Now, if you want to turn this on its head, you can repeat something until your boolean becomes true. This works like so:

[applescript]
repeat while x is false
--code to repeat
end repeat
[/applescript]

This all seems a little abstract, so let's do something interesting with a repeat while loop. We'll build a basic number guessing game. First, we'll set the answer variable to a random number and our guess variable to 0. Next, we'll create a repeat while loop that keeps going as long as the user's guess is not equal to the randomly selected answer.

Inside the repeat, we'll display a dialog and set the number returned to the guess variable. This guess entry window will persist until the guess is correct.

[applescript]
set answer to random number from 1 to 5
set guess to 0
repeat while guess is not equal to answer
set guess to text returned of (display dialog "Guess again! Choose a number from 1 to 5" default answer "1") as number
end repeat
display dialog "That's right! " & answer & " is the answer!"
[/applescript]

This window allows the user to guess a number and will repeat until the guess is correct.

Repeat Until

The code "repeat while guess is not equal to answer" is not very easy to read. The negative (not equal to) makes it confusing. We can simplify this a little bit if we ditch the repeat while loop and instead look to a repeat until loop. Here's the number guess game rewritten:

[applescript]
set answer to random number from 1 to 5
set guess to 0

repeat until (guess = answer)
set guess to text returned of (display dialog "Guess again! Choose a number from 1 to 5" default answer "1") as number
end repeat

As you can see, this repeat is much more succinct and easy to read. Keep in mind that this won't always be the case, sometimes a repeat while will be the one that saves you code.

All Together Now

Whew! There are an awful a lot of different types of repeat loops aren't there? If you're feeling overwhelmed, don't be. They're all fairly simple and you'd be surprised how often the right wording is the first thing that pops into your head. Just to keep you on track, here's a quick list of some different repeat examples:

repeat 5 times

repeat n times

repeat with n from 1 to 5

repeat with listItem in theList

repeat while x

repeat while y is true

repeat while x is false

repeat until y

repeat until (x > y)

When writing a repeat loop, always run through a few other structures in your head to see if you can make it briefer and more succinct. As we saw above, you can really improve your code by staying open to using different constructs.

Stay In The Loop

You should now be an expert on AppleScript repeat loops. By leveraging these in conjunction with if statements, which we learned about before, you'll be able to pull off some unbelievably complex and useful scripts.

In fact, in our next AppleScript article will take a break from theory and put some of this knowledge to use with a practical script that you can implement on your system right away. Check back soon!