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 7if size is more than 5 printline "That's a big one"endThat's a big onesize = 7if (size > 5) { printline("That's a big one")}That's a big oneYou can write comparisons in words or in symbols. They mean the same:
| In words | Symbol |
|---|---|
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 55if 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"endPassgrade = 55if (grade >= 70) { printline("Distinction")} else if (grade >= 50) { printline("Pass")} else { printline("Try again")}Passand, or
Section titled “and, or”Join conditions with and and or, or with && and ||:
set size to 7if size is more than 5 and size is less than 10 printline "Just right"endif size is less than 3 or size is more than 6 printline "Too small or too big"endJust rightToo small or too bigsize = 7if (size > 5 && size < 10) { printline("Just right")}if (size < 3 || size > 6) { printline("Too small or too big")}Just rightToo small or too bigTesting text
Section titled “Testing text”Three handy tests for text:
set name to "report.pdf"if mash.str(name).endsWith(".pdf") printline "ends with .pdf"endif "pdf" in name printline "contains pdf"endif name matches /\.pdf$/ printline "matches the pattern"endends with .pdfcontains pdfmatches the patternname = "report.pdf"if (mash.str(name).endsWith(".pdf")) { printline("ends with .pdf")}if ("pdf" in name) { printline("contains pdf")}if (name matches /\.pdf$/) { printline("matches the pattern")}ends with .pdfcontains pdfmatches the patternThe last one is a regular expression, a pattern language for text. The language reference covers it.
What counts as false
Section titled “What counts as false”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"endno titletitle = ""if (title) { printline("has a title")} else { printline("no title")}no titleFor a quick either-or value, use condition ? this : that:
set size to 4printline size is more than 3 ? "big" : "small"bigsize = 4printline(size > 3 ? "big" : "small")bigeach 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}}"endNumber 1Number 2Number 3each (1...3) as number { printline("Number {{number}}")}Number 1Number 2Number 3as 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}}"endI'd like some applesI'd like some bananasI'd like some cherriesfruits = ["apples", "bananas", "cherries"]each (fruits) as fruit { printline("I'd like some {{fruit}}")}I'd like some applesI'd like some bananasI'd like some cherriesA 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}}"endapples: 12bananas: 0stock = {apples: 12, bananas: 0}each (stock) as item, count { printline("{{item}}: {{count}}")}apples: 12bananas: 0Loops nest. Here’s a small times table:
each 1...2 as row each 1...3 as col printline "{{row}} x {{col}} = {{row * col}}" endend1 x 1 = 11 x 2 = 21 x 3 = 32 x 1 = 22 x 2 = 42 x 3 = 6each (1...2) as row { each (1...3) as col { printline("{{row}} x {{col}} = {{row * col}}") }}1 x 1 = 11 x 2 = 21 x 3 = 32 x 1 = 22 x 2 = 42 x 3 = 6Both
each 1...3 as iandeach i in 1...3work. 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.
Skipping and stopping
Section titled “Skipping and stopping”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 nend1357each (1...10) as n { if (n % 2 == 0) { next } if (n > 7) { break } printline(n)}1357while and until
Section titled “while and until”while repeats as long as a condition is true. until repeats until it becomes true:
set n to 0while n is less than 3 printline "n is {{n}}" increment nendn is 0n is 1n is 2n = 0while (n < 3) { printline("n is {{n}}") n += 1}n is 0n is 1n is 2set n to 0until n is 3 increment nendprintline "Stopped at {{n}}"Stopped at 3n = 0until (n == 3) { n += 1}printline("Stopped at {{n}}")Stopped at 3Make 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.
Try it
Section titled “Try it”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.