I'm a Python programmer who switched to Mac OS X. Being nerd and needing to automate common tasks, the learning of the AppleScript language was unavoidable. To speed up the process I've took some notes, comparing the new commands to Python statements. The result is this document.
As the name says, it's intended for Python programmers. But if you're an applescripter interested in Python you may also learn a lot.
| Python | AppleScript |
|---|---|
| indexes start with 0 | indexes start with 1 |
| string comparison considers case | string comparison ignores case |
| # comments | -- comments |
| command # half-line comment | command -- half-line comment |
|
""" multiline comment block (sort of) """ |
(* multiline comment block *) |
| a = 5 | set a to 5 |
| a = "foo" | set a to "foo" |
| print "Hello World" | display dialog "Hello World" |
|
syslog.syslog(msg) or print >>sys.stderr, msg |
log(msg) |
| print "\a" | beep |
| say "Hello World" | |
| Data types | |
| type("foo").__name__ | class of "foo" |
| None | missing value |
| True, False | true, false |
| 2 | 2 |
|
"foo" or 'foo' |
"foo" |
|
"""foo bar""" |
"foo bar" |
| [ 1, 2, 3 ] | { 1, 2, 3 } |
| ( 1, 2, 3 ) | |
| { "foo": "bar" } | { foo: "bar" } |
| str(5) | 5 as text |
| int("5") | "5" as integer |
| float(5) | 5 as real |
| float("5") | "5" as real |
| list("foo") | characters of "foo" |
| "".join([ "f","o","o" ]) | { "f","o","o" } as text |
| "".join([str(x) for x in [ 1, 2, 3 ]]) | { 1, 2, 3 } as text |
| String | |
| S = "" | set S to "" |
| S = "foo" | set S to "foo" |
| len(S) |
length of S or count S |
| S[2] | item 3 of S |
| S[len(S)/2] | middle item of S |
| S[random.randint(0, len(S)-1)] | some item of S |
| S[2:-2] | items 3 thru -3 of S as text |
| S + "foo" | S & "foo" |
|
S.index("z") or S.find("z") |
offset of "z" in S |
| S.startswith("z") | S starts with "z" |
| S.endswith("z") | S ends with "z" |
| S.count("z") | User function countSubstring() |
| S.split() | words in S |
| S.split()[2] | word 2 of S |
| S.split(":") |
set AppleScript's text item delimiters to ":" text items of S set AppleScript's text item delimiters to "" |
| ":".join(LIST) |
set AppleScript's text item delimiters to ":" LIST as text set AppleScript's text item delimiters to "" |
| S.lstrip() | User function lstripString() |
| S.rstrip() | User function rstripString() |
| S.strip() | User function stripString() |
| S.lower() | User function lowerString() |
| S.upper() | User function upperString() |
| S.capitalize() | User function capitalizeString() |
| S.replace() | User function replaceString() |
| "z" in S | "z" is in S |
| \\ \" \t \n \r | \\ \" \t \r space tab return |
| S = "foo\nbar" | set S to "foo" & return & "bar" |
| S = """foo "bar" baz""" | set S to "foo \"bar\" baz" |
| List | |
| L = [] | set L to {} |
| L = [ 77, "foo", True ] | set L to { 77, "foo", true } |
| L = [ 1, [ 2, [ 3 ]]] | set L to { 1, { 2, { 3 }}} |
| len(L) |
length of L or count L |
| [x for x in L if isinstance(x, int)] | integers in L |
| [x for x in L if isinstance(x, str)] | strings in L |
| L[2] | item 3 of L |
| L[2][2] | item 3 of item 3 of L |
| L[len(L)/2] | middle item of L |
| L[random.randint(0, len(L)-1)] | some item of L |
| newlist = L[:] |
set newlist to every item of L or copy L to newlist |
| L[2:-2] | items 3 thru -3 of L |
|
L + [ 1, 2 ] or L.extend([ 1, 2 ]) |
L & { 1, 2 } |
| L.append("foo") |
set the end of L to "foo" or copy "foo" to the end of L |
| L[2] = "foo" | set item 3 of L to "foo" |
| del L[2] | set L to items 1 thru 2 of L & items 4 thru -1 of L |
| L.index("foo") | User function getListItemIndex() |
| L.count("foo") | User function countListItem() |
| L.pop(0) |
first item of L set L to rest of L |
| L.pop(0) ; L[:] | rest of L |
| L.reverse() | reverse of L |
| L.sort() | |
| "foo" in L | "foo" is in L |
| L[0] == "foo" | L starts with "foo" |
| L[-1] == "foo" | L ends with "foo" |
| Dictionary / Record | |
| D = {} | set D to {} |
| D = { "foo":"bar", "spam":"eggs" } | set D to { foo:"bar", spam:"eggs" } |
| len(D) |
length of D or count D |
| D["foo"] | foo of D |
| D["foo"] = "bar" | set foo of D to "bar" |
|
D + { "foo":"bar" } or D.update({ "foo":"bar" }) |
D & { foo:"bar" } |
| newdic = D.copy() | copy D to newdic |
| del D["foo"] | |
| D.keys() | |
| D.values() | |
| D.has_key() | |
| D["foo"] == "bar" | foo of D is "bar" |
| D.get("foo") == "bar" | { foo:"bar" } is in D |
| Expressions | |
| 1 + 1 | 1 + 1 |
| 1 - 1 | 1 - 1 |
| 1 * 1 | 1 * 1 |
| 1 / 1 | 1 div 1 |
| 1.0 / 1.0 |
1 / 1 or 1 ÷ 1 |
| 1 % 1 | 1 mod 1 |
| 1 ** 1 | 1 ^ 1 |
| (2 + 4) * 2 | (2 + 4) * 2 |
| 1 == 1 |
1 = 1 or 1 is equal 1 |
| 1 != 1 |
1 ≠ 1 or 1 is not equal 1 |
| 1 > 1 |
1 > 1 or 1 is greater than 1 |
| 1 < 1 |
1 < 1 or 1 is less than 1 |
| 1 >= 1 |
1 >= 1 or 1 ≥ 1 or 1 isn't less than 1 |
| 1 <= 1 |
1 <= 1 or 1 ≤ 1 or 1 isn't greater than 1 |
| 1 is 1 | 1 is 1 |
| 1 is not 1 | 1 is not 1 |
| 1 is 1 or 2 is 2 | 1 is 1 or 2 is 2 |
| 1 is 1 and 2 is 2 | 1 is 1 and 2 is 2 |
| (1 is 1) and (2 is 2) | (1 is 1) and (2 is 2) |
| Conditionals | |
| if VAR == 1: print "OK" | if VAR = 1 then display dialog "OK" |
|
if VAR == 1: print "OK" |
if VAR = 1 then display dialog "OK" end if |
|
if VAR == 1: print "OK" else: print "Error" |
if VAR = 1 then display dialog "OK" else display dialog "Error" end if |
|
if VAR < 10: print "Need more!" elif VAR > 20: print "Too much!" else: print "It's OK" |
if VAR < 10 then display dialog "Need more!" else if VAR > 20 then display dialog "Too much!" else display dialog "It's OK" end if |
| Loops | |
|
for i in LIST: print i |
repeat with i in LIST display dialog i end repeat |
|
while 1: break |
repeat exit repeat end repeat |
|
while 1: continue |
|
|
while VAR is False: # do something |
repeat while VAR is false -- do something end repeat |
|
while VAR is not False: # do something |
repeat until VAR is false -- do something end repeat |
|
for i in range(10): # do something |
repeat 10 times -- do something end repeat |
|
for i in range(1, 10, 2): # do something |
repeat with i from 1 to 10 by 2 -- do something end repeat |
| Functions | |
|
def add_numbers(a, b): return a + b |
on add_numbers(a, b) return a + b end add_numbers |
| five = add_numbers(2, 3) | set five to add_numbers(2, 3) |
| def optional(a=0, b=""): | |
| Class / Script | |
|
class FooBar(Father): VAR = 0 def setValue(self, val): self.VAR = val |
script FooBar property parent : Father property VAR : 0 on setValue(val) set my VAR to val end setValue end script |
|
myFoo = FooBar() myFoo.setValue(5) myData = myFoo.VAR |
copy FooBar to myFoo tell myFoo to setValue(5) set myData to VAR of myFoo |
| File Read/Write | |
|
F = open("/tmp/foo") TXT = F.read() F.close() |
set F to "/tmp/foo" as POSIX file set TXT to read F |
|
F = open("/tmp/foo") LINES = F.readlines() F.close() |
set F to "/tmp/foo" as POSIX file set LINES to read F using delimiter (ASCII character 10) |
|
F = open("/tmp/foo", "w") F.write("Hello!\n") F.close() |
set F to "/tmp/foo" as POSIX file set F to open for access F with write permission write "Hello!" & return to F close access F |
|
Path (requires tell app "Finder") |
|
| os.path.isfile(F) | file F exists |
| os.path.isdir(F) | folder F exists |
| os.path.abspath(F) | file F as text |
| os.path.dirname(F) | folder of file F as text |
| os.path.basename(F) | name of file F |
| F.split(os.path.extsep)[-1] | name extension of file F |
| os.stat(F)[6] | size of file F |
| pwd.getpwuid(os.stat(F)[4])[0] | owner of file F |
| grp.getgrgid(os.stat(F)[5])[0] | group of file F |
| open(newfile, "w").write(open(F).read()) | duplicate file F to file newfile |
| os.rename(F, newfile) | set name of file F to newfile |
| os.unlink(F) | delete file F |
| Date & Time | |
| time.asctime() | current date as string |
| T = time.localtime() | set T to current date |
|
T = time.strptime( "Jan 31, 2005 17:59", "%b %d, %Y %H:%M" ) |
set T to date "Jan 31, 2005 17:59" |
|
orig = time.mktime(time.strptime( "Jan 31, 2005 17:59", "%b %d, %Y %H:%M" )) plus = time.mktime(time.strptime( "4 3 2 1970", "%d %H %M %Y" )) T = time.localtime(orig+plus) |
set orig to date "Jan 31, 2005 17:59" set plus to 4 * days + 3 * hours + 2 * minutes set T to orig + plus |
| time.strftime("%A", T) | weekday of T |
| time.strftime("%d", T) | day of T |
| time.strftime("%B", T) | month of T |
| time.strftime("%m", T) | month of T as integer |
| time.strftime("%Y", T) | year of T |
| time.strftime("%X", T) | time string of T |
| time.strftime("%x", T) | date string of T |
|
fmt = "%H*3600 + %M*60 + %S" eval(time.strftime(fmt, T)) |
time of T -- Seconds since midnight |
| Other | |
|
try: # do something except: # do something |
try -- do something on error -- do something end try |
|
try: # do something except error, errmsg: # do something |
try -- do something on error errMsg number errNum -- do something end try |
| os.system("ls /etc/ | head -n 1") | do shell script "ls /etc/ | head -n 1" |
| global VAR | global VAR |
| eval("4 + 4") | run script "4 + 4" |
| chr(64) | ASCII character 64 |
| ord("@") | ASCII number "@" |
| time.sleep(10) | delay 10 |
| random.randint(5, 10) | random number from 5 to 11 |
| foo, bar = 1, 2 | set {foo, bar} to {1, 2} |
|
D = {"foo":1, "bar":2 } var1, var2 = D["foo"], D["bar"] |
set {var1, var2} to {foo, bar} of {foo:1, bar:2} |
| [ 0, 1, { "foo":"bar" }][2]["foo"][0] | character 1 of foo of item 3 of {0, 1, {foo:"bar"}} |
|
import foo foo.do_something() |
set foo to load script "foo.scpt" tell foo to do_something() |
| "a" == "A" # returns False |
"a" = "A" -- returns true considering case "a" = "A" -- returns false end considering |
| "1 2 3 4" == "1234" # returns False |
"1 2 3 4" = "1234" -- returns false ignoring white space "1 2 3 4" = "1234" -- returns true end ignoring |
| sys.exit() | tell me to quit |
Handy functions
The AppleScript language is very limited on data handling. The programmer must build his own tools (functions) to have Python-like functionality to manage strings and lists.
countSubstring()
-- Counts how many times a string appears in a text -- Note: Its splits the text by the substring and count the items -- on countSubstring(theText, theSubstring) set AppleScript's text item delimiters to theSubstring set counter to (count of every text item of theText) - 1 set AppleScript's text item delimiters to "" return counter end countSubstring
lstripString()
-- Trims the provided string from the text's beginning
--
on lstripString(theText, trimString)
set x to count trimString
try
repeat while theText begins with the trimString
set theText to characters (x + 1) thru -1 of theText as text
end repeat
on error
return ""
end try
return theText
end lstripString
rstripString()
-- Trims the provided string from the text's ending
--
on rstripString(theText, trimString)
set x to count trimString
try
repeat while theText ends with the trimString
set theText to characters 1 thru -(x + 1) of theText as text
end repeat
on error
return ""
end try
return theText
end rstripString
stripString()
-- Trims the provided string from the text's boundaries -- Note: Requires the lstripString and rstripString functions -- on stripString(theText, trimString) set theText to lstripString(theText, trimString) set theText to rstripString(theText, trimString) return theText end stripString
lowerString() / upperString() / capitalizeString()
-- Translate characters of a text
-- Note: Pass the From and To tables as strings (same lenght!)
--
on translateChars(theText, fromChars, toChars)
set the newText to ""
if (count fromChars) is not equal to (count toChars) then
error "translateChars: From/To strings have different lenght"
end if
repeat with char in theText
set newChar to char
set x to offset of char in the fromChars
if x is not 0 then set newChar to character x of the toChars
set newText to newText & newChar
end repeat
return the newText
end translateChars
-- Convert a text case to lower characters
-- Note: Requires the translateChars function
--
on lowerString(theText)
set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set lower to "abcdefghijklmnopqrstuvwxyz"
return translateChars(theText, upper, lower)
end lowerString
-- Convert a text case to upper characters
-- Note: Requires the translateChars function
--
on upperString(theText)
set lower to "abcdefghijklmnopqrstuvwxyz"
set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
return translateChars(theText, lower, upper)
end upperString
-- Capitalize a text, returning only the first letter uppercased
-- Note: Requires translateChars, lowerString and upperString
--
on capitalizeString(theText)
set firstChar to upperString(first character of theText)
set otherChars to lowerString(characters 2 thru -1 of theText)
return firstChar & otherChars
end capitalizeString
replaceString()
-- Replace all occurences of one string for another in a text -- The trick here is to change the internal delimiter, -- spliting and joining the text -- on replaceString(theText, oldString, newString) set AppleScript's text item delimiters to oldString set tempList to every text item of theText set AppleScript's text item delimiters to newString set theText to the tempList as string set AppleScript's text item delimiters to "" return theText end replaceString
getListItemIndex()
-- Returns the integer index of a list item (zero if not found)
--
on getListItemIndex(theList, theItem)
repeat with i from 1 to count of theList
if item i of theList is theItem then return i
end repeat
return 0
end getListItemIndex
countListItem()
-- Returns the total count of a specific item in a list
--
on countListItem(theList, theItem)
set counter to 0
repeat with i from 1 to count of theList
if item i of theList is equal to theItem then
set counter to counter + 1
end if
end repeat
return counter
end countListItem
Thank You Very Much!
This document was reviewed and got valuable contributions from:
- Alfredo Kojima
- André Ruiz
- Osvaldo Santana Neto
- Rudá Moura
- Ryan Wilcox
- Sérgio Bruder
— EOF —