Bash でやってることを AppleScript でやろうとするとこうなる

More than 1 year has passed since last update.

AppleScript を使い始めた頃「シェルスクリプトは書けるけど AppleScript ではどう書くの?」と悩んだので復習もかねて書いてみました。イコールではない部分もあります。書いているうちに色々増えてしまったのでちょっと見づらいかも。

変数

代入

基本は set 変数名 to 値 という書き方。レコードに関しては省略します。

Bash AppleScript
foo=1 set foo to 1
foo=bar set foo to "bar"
foo+=$bar set foo to foo & bar
foo=()
declare -a foo
set foo to {}
foo=(a b c) set foo to {"a", "b", "c"}

"every ~ of" によるリスト化
文字単位:set foo to every character of "abc"
単語単位:set foo to every word of "My name is foo"
改行単位:set foo to every paragraph of "My name is foo.\nHis name is bar."
デリミタ単位:set foo to every text item of "first, second, third"

※デリミタについては下の補足を見て下さい
foo="${bar[*]}" set text item delimiters of AppleScript to space
set foo to bar as string
foo=(bar "${foo[@]}") set beginning of foo to "bar"
set foo to {"bar"} & foo
foo=("${foo[@]}" bar)
foo[${#foo[@]}]=bar
set end of foo to "bar"
set foo to foo & {"bar"}
set foo to foo & "bar"
foo=$((1 + 1))
foo=$(echo ~)
foo="$(ls)"
foo="$(\ls)"
※コマンドの結果を代入する例です
set foo to 1 + 1
set foo to path to home folder
set foo to do shell script "ls"
set foo to do shell script "\\ls"

リスト作成時、最初のカンマは許容されるけど最後のカンマはダメ。

set foo to {, "a", "b"} -- OK
set foo to {"a", "b", } -- NG

set beginning の場合、最初に文字列を書いてしまうとリストは文字列に変換される。

set foo to {"a", "b"}
set beginning of foo to "0" & foo -- "0ab" という文字列になってしまう

property を使うと異なるハンドラ間で変数が使用可能。

property foo : missing value

on main()
    set foo to "bar"
end main

on run
    main()
    return foo -- `property' が無い場合はここでエラー
end run

日本語で every word of を使う場合はどのように分割されるかチェックしておいた方がいいかも。

set foo to every word of "東京都 港区"
--> result: {"東京", "都", "港区"}

every text item of の補足

AppleScript のデリミタは {""} がデフォルトです。そのままだと every character of と同じ分割になります。任意の文字で分割したい場合はデリミタを変更します。デリミタは文字列での指定も可能なので例えばカンマの後にスペースが入る規則であれば ", " という指定も可能です。

set text item delimiters of AppleScript to ","
every text item of "東京都, 港区"
--> result: {"東京都", " 港区"} <-- スペースが残ってしまう

set text item delimiters of AppleScript to ", "
every text item of "東京都, 港区"
--> result: {"東京都", "港区"}

デリミタにリストを指定した場合は各要素によって分割されます。ただし、単純にその文字で分割するだけで単語的な意味では分割しません。

set text item delimiters of AppleScript to every character of "都道府県" --> {"都", "道", "府", "県"}
every text item of "東京都大阪府京都府北海道"
--> result: {"東京", "大阪", "京", "", "北海", ""}

"参照" と "コピー"

AppleScript では変数の値に変数(名)を設定した場合、"参照"になることがあります。

set foo to {1, 2}
set bar to foo
set item 1 of foo to true
log foo & bar
--> result: true, 2, true, 2 <-- foo への変更が bar にも反映される

copycontents of を使うことで値そのものを複製できます。

set foo to {1, 2}
copy foo to bar
set item 1 of foo to true
log foo & bar
--> result: true, 2, 1, 2
set foo to {1, 2}
set bar to contents of foo
set item 1 of foo to true
log foo & bar
--> result: true, 2, 1, 2

参照

Bash AppleScript
$foo foo
"$foo" quoted form of foo
${#foo} count foo または length of foo
${foo[@]} foo
"${foo[@]}" foo(※下の「ダブルクオート付き配列展開」の項に追記あり)
${foo[*]}
"${foo[*]}"
set text item delimiters of AppleScript to space
foo as string
${#foo[@]} count foo または length of foo
※if で count を使う場合は if (count of foo) と書かないとエラーになる。
${foo[0]}
${foo[n]}
item 1 of foo
item n of foo(※Bash側の値+1)
${foo[0]} beginning of foo
${foo[@]:${#foo[@]}}
${foo[${#foo[@]} - 1]}
end of foo または item -1 of foo
$PATH system attribute "PATH"
$HOME POSIX path of (path to home folder)
system attribute "HOME"
$TMPDIR POSIX path of (path to temporary items)(※$TMPDIR/TemporaryItems/)
system attribute "TMPDIR"
$RANDOM random number(※デフォルトは 0.0〜1.0 の範囲)
random number from 0 to 32767

※"from ~" または "to ~" のみでも指定可
random number from 32767
random number to 32767

path to ~alias Macintosh HD: で返って来るので Unix パスにする場合は POSIX path of で変換する。alias はフォルダの場合最後に ":" が付くので POSIX path of で変換すると最後に / が付く。これは thru -2 で取り除ける。

POSIX path of (path to library folder from user domain)
--> result: "/Users/foo/Library/"

items 1 thru -2 of POSIX path of (path to library folder from user domain) as string
--> result: "/Users/foo/Library"

do shell script などに渡す場合、クオートする必要があれば quoted form of を使うとシングルクオートで囲ってくれる。

do shell script "ls \"" & POSIX path of (path to me) & "\""
do shell script "ls '" & POSIX path of (path to me) & "'"

-- quoted form of を使うと楽
do shell script "ls " & quoted form of POSIX path of (path to me)

特殊変数

on run argvon open argv で引数が使える。

on run argv
    return argv
end run
Bash AppleScript 備考
$0
  • POSIX path of (path to)
  • POSIX path of (path to me)
  • POSIX path of (path to it)
アプリケーションの場合は foo.app までのパス。
"$0" quoted form of POSIX path of (path to me) quoted form of と上記のどれか。
$1 .. $n item 1 of argv .. item n of argv
$1 beginning of argv
${!#}
${@:$#}
end of argv または
item -1 of argv
$# count argv または
length of argv
$*
"$*"
text item delimiters of AppleScript to space
argv as string
デリミタをスペースに変更してから変換する。
as stringas text どちらでも可。
$@ argv osascript の場合、デフォルトは foo, bar のようなカンマ区切り。
-s s オプションを使用した場合は {"foo", "bar"} で返る。
"$@" argv 下の「ダブルクオート付き配列展開」の項に追記あり
IFS
  • text item delimiters of AppleScript
  • AppleScript's text item delimiters
デフォルトは {""}。文字列またはリストが指定可能。
shift set argv to rest of argv または
set argv to items 2 thru -1 of argv
shift 2 set argv to items 3 thru -1 of argv AppleScript の場合は items 数が要素数を上回るとエラーになるので注意。

制御文字

ダブルクオートの外に書く場合、"string" & return & "string" のように連結が可能。ダブルクオート内でバックスラッシュを用いて書いた場合は AppleScript エディタによって勝手に変換される。

Bash AppleScript
\n return
\s space
\t tab

if

1行の場合は end if を省略。

if "a" = "a" then return true

否定は (option + =)。また isis not という書き方もある(いっぱいありすぎるので公式リファレンス見て下さい)。※ここの条件式は適当です

if "a" = "a" then
    log
else if "a"  "a" then
    log
else if "b" is "b" then
    log
else if "b" is not "b" then
    log
else if "a" = "a" and "b" = "b" then
    log
else if "a" = "a" or "b" = "b" then
    log
else
    log
end if

メモ:if count foo = 0 という記述だとエラーになるので if length of fooif (count of foo) を使う。

while/for

breakexit repeat。これらの他に repeat number times もあります。

while read

every paragraph of で改行区切りのリストとして読み込みます。

repeat with x in every paragraph of (do shell script "ls -1")
    log x
end repeat

ダブルクオートで書けばヒアドキュメント(?)扱い。

repeat with x in every paragraph of "a
b
c"
    log x
end repeat

while :(無限ループ)

※真偽値の場合は repeat while bool があります。

set foo to 0
repeat
    if foo is less than 10 then
        set foo to foo + 1
    else
        exit repeat
    end if
end repeat
return foo --> result: 10

for ~ in ~

repeat with x in argv
     log x
end repeat

repeat with x in every word of "first second third"
    log x
end repeat

for i in {0..9} / for ((i=0; i<10; i++))

repeat with i from 0 to 9
    log i
end repeat

continue

bash の continue に相当するものは無いようですが、ダミーループを使うことで continue のようなものを再現できるようです。

repeat with i from 0 to 9
    repeat 1 times
        if i = 5 then exit repeat
        log i
    end repeat
end repeat

参考:http://stackoverflow.com/questions/1024643/applescript-equivalent-of-continue

case

AppleScript にはワイルドカード的なものが無いっぽい(?)けど前方一致や後方一致がある。

foo=AppleScript

Bash AppleScript
case $foo in App*) ;; esac if foo starts with "App" then
case $foo in *ript) ;; esac if foo ends with "ript" then
case $foo in *Sc*) ;; esac if foo contains "Sc" then
case $foo in *[AS]*) ;; esac if foo contains "A" or foo contains "S" then
shopt -s nocasematch
case $foo in *s*) ;; esac
ignoring case
    if foo contains "s" then
end ignoring
case $foo in ?p*) ;; esac if item 2 of foo is "p" then
case $foo in ?ppl*) ;; esac if items 2 thru 4 of foo as string is "ppl" then
if items 2 thru 4 of foo is {"p", "p", "l"} then

test -f / test -d

info for でエイリアスの情報を取得し、folder ラベルから真偽値を取り出します。

tell application "Finder" to set selections to selection as alias list
repeat with x in selections
    if folder of (info for x) = true then
        log "This is folder"
    else
        log "This is file"
end if

tell application "Finder" to repeat with ~ in selection as alias list の場合はレコードから値を取り出せないことがあるようです。

function

AppleScript では「ハンドラ」。on name() から end name まで。

runopenreopenidlequit は特別。

on x(input)
    log input
end x

on y(aNumber, bNumber)
    log aNumber + bNumber
end y

x("string") --> result: string
x({1, 2}) --> result: 1, 2
y(1, 2) --> result: 3

"$@"(ダブルクオート付き配列展開)

quoted form of したリストに置き換えるかリストを別に作成する。

set foo to {"my home", "my room"}
repeat with i from 1 to count foo
    set item i of foo to quoted from of item i of foo
end repeat
set foo to {"my home", "my room"}
set bar to {}
repeat with x in foo
    set end of bar to quoted form of x
end repeat

do shell script 行ではリストは勝手に as string されるためデリミタをスペースに変更しておく。

set text item delimiters of AppleScript to space
do shell script "sh -c 'echo $#' -- " & foo -- 新しいリストを作成した場合はその変数
--> result: 2

if ! command; then command; fi や (command) || command のようなもの

Bash で set -e してるような状態だと思って下さい。try を使うことでエラー時の対応をしたり、スクリプトの終了を回避できます。false ではなくエラーになった場合なのでちょっと意味が違うかもしれません。例ではわざと-128 のエラーを発生させています。

try
    error number -128 -- try 内で実行されているのでエラーが起きても終了しない
end try
log "end" -- 処理される

(command) || { echo error; exit 1; }

osascript の場合、exit 0 で終了する場合は error ではなく return とします。

try
    error number -128 -- このエラーでは終了しない
on error
    log "エラーが発生しました"
    error -- ここで終了する
end try
log "end" -- 終了済みなのでここは処理されない

バックスラッシュ

改行前の "\"

option + l の "¬" を使うことで折り返しが可能。改行不可な場所もあるので注意。

set aList to { ¬
  "a", ¬
  "b"}

do shell script 内での "\"

\ は AppleScript の \ として扱われるので do shell script 内では \\\\

do shell script "echo \"\\n\""

echo 的なもの

AppleScript は文字列を書けばそのまま出力されます。また、途中のものは出力されず最後の結果のみ出力されます。

"foo"
"hoge"
--> result: hoge

log を使うことでイベントログ側に出力結果が残ります。osascript の場合は標準エラー出力に出力されます。

log "foo"
log "bar"
--> result:
--> ログに (*foo*) と (*bar*) が出力されます。

コメント

ダブルクオートされていない -- 以降、もしくは (* から *) で囲まれた範囲。

補足

text item delimiters of AppleScript の戻しに関しては省略しています。使用後は元に戻しておくことをおすすめします。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.