Skip to content

Decisions and loops

So far every script has run top to bottom, once. Real jobs need choices (“is this a PDF?”) and repetition (“do this for every file”).

if runs some lines only when a condition is true. Every if ends with end:

set size to 7
if size is more than 5
printline "That's a big one"
end
That's a big one

You can write comparisons in words or in symbols. They mean the same:

In wordsSymbol
is==
is not!=
is less than<
is less than or equal to<=
is more than>
is more than or equal to>=

Add else for the other case, and else if for more cases. MaSH tries them in order and runs the first that matches:

set grade to 55
if grade is more than or equal to 70
printline "Distinction"
else if grade is more than or equal to 50
printline "Pass"
else
printline "Try again"
end
Pass

Join conditions with and and or, or with && and ||:

set size to 7
if size is more than 5 and size is less than 10
printline "Just right"
end
if size is less than 3 or size is more than 6
printline "Too small or too big"
end
Just right
Too small or too big

Three handy tests for text:

set name to "report.pdf"
if mash.str(name).endsWith(".pdf")
printline "ends with .pdf"
end
if "pdf" in name
printline "contains pdf"
end
if name matches /\.pdf$/
printline "matches the pattern"
end
ends with .pdf
contains pdf
matches the pattern

The last one is a regular expression, a pattern language for text. The language reference covers it.

Besides false, these all count as false in an if: null, 0, the empty string "" and the empty array []. Everything else is true. That lets you write short checks:

set title to ""
if title
printline "has a title"
else
printline "no title"
end
no title

For a quick either-or value, use condition ? this : that:

set size to 4
printline size is more than 3 ? "big" : "small"
big

each repeats some lines for every item in a list. The simplest list is a range, written 1...5 (one to five, both included):

each 1...3 as number
printline "Number {{number}}"
end
Number 1
Number 2
Number 3

as number gives each item a name inside the loop. Use ..< to stop one short: 1..<4 is 1, 2 and 3.

An array works the same way:

set fruits to ["apples", "bananas", "cherries"]
each fruits as fruit
printline "I'd like some {{fruit}}"
end
I'd like some apples
I'd like some bananas
I'd like some cherries

A dictionary has keys as well as values. Name both, separated by a comma:

set stock to {apples: 12, bananas: 0}
each stock as item, count
printline "{{item}}: {{count}}"
end
apples: 12
bananas: 0

Loops nest. Here’s a small times table:

each 1...2 as row
each 1...3 as col
printline "{{row}} x {{col}} = {{row * col}}"
end
end
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6

Both each 1...3 as i and each i in 1...3 work. They mean the same.

..< leaves the end out in either direction, and it gives an empty list when the two ends are equal: 5..<1 is 5, 4, 3 and 2, and 0..<0 is empty.

next jumps straight to the next item. break leaves the loop altogether:

each 1...10 as n
if n % 2 is 0
next
end
if n is more than 7
break
end
printline n
end
1
3
5
7

while repeats as long as a condition is true. until repeats until it becomes true:

set n to 0
while n is less than 3
printline "n is {{n}}"
increment n
end
n is 0
n is 1
n is 2
set n to 0
until n is 3
increment n
end
printline "Stopped at {{n}}"
Stopped at 3

Make sure something inside the loop changes the condition. A loop that can never finish is stopped by Foldr when the script runs out of time, but you’ll get a failed run in the log.

Print the numbers from 1 to 20. Print “Fizz” instead of any number divisible by 3. Hint: n % 3 is 0.

Next, you’ll learn to keep a lot of values together.