AppleScriptから実行させるコマンドのパスにスペースがあるとエラーになる問題を解決

AppleScriptからコマンドを実行させようとするとき、スペースが入ったパスが含まれるとエラーになる問題があります。これを解決する方法。

スペースを含むパスをコマンドに含めたときのエラー

コマンドラインでパスを含めるとき、スペースが入っているとまずいことになります。例えばこんな。

ls -l /Volumes/Drobo 5D/Art/

パス中のスペースを命令文の区切りと解釈するのでエラーになります。そのため、スペースをエスケープします。「 \ 」を使いますね。

ls -l /Volumes/Drobo\ 5D/Art/

あるいはダブルクォーテーションで括ります。

ls -l "/Volumes/Drobo 5D/Art/"

ここまでは誰でも知ってます。問題は、コマンドをAppleScriptから送信するときです。

AppleScriptからコマンドを実行させるには do script を使います。まったくド素人なので意味はわかりませんが、こんなふうに書きます。

tell application "Terminal"
 activate
 do script with command "ここにコマンド"
end tell

命令文は、いろんな情報によりますと以下のどれでも良いっぽいです。違いはわかりません。同じような挙動です。

do script “コマンド”
do shell script “コマンド”
do script with command “コマンド”

※ あとで気づきましたが、do shell script ではちゃんと動かないことが多いですね

いずれにしろ、この命令文に、上記の例で挙げたコマンドを当てはめると、こうなると考えるわけですが

do script with command "ls -l /Volumes/Drobo\ 5D/Art/"

これではエラーになります。じゃあ、と

do script with command "ls -l '/Volumes/Drobo\ 5D/Art/'"

こう書いても

do script with command "ls -l /Volumes/'Drobo 5D'/Art/"

こうしても

do script with command "ls -l \"/Volumes/Drobo\ 5D/Art/\""

すべてエラーで動きません。

わけわからないので、「素人が手を出すんじゃねえ」とか「do script は使えないやつ」とか「どうせ酸っぱいさ」と納得し、長い間放置していました。前にも書いたとおり、コピペで賄ってきたんです。コピペ最強。

でもですね、別アプリから連続処理でコマンドを実行させようとしたらえらいことになります。コピペごとにアプリウインドウとターミナルウインドウがチラチラと高速で点滅し見ていられない状況になりますね。
これはダサい。何とか解決できる術はないのかと必死に・・・嘘です、気長に解決の糸口を探していました。で、ひょんな事で答えを見つけて小躍りして喜んだのは私です。

AppleScriptからスペースを含んだパスを含むコマンドをターミナルにエラーなく送る方法

それはこうです。

tell application "Terminal"
	activate
	set thePath to quoted form of "パス"
	do script with command "コマンド" & thePath
end tell

パスを変数 thePath に収めますが、このときクォートの指定みたいなのを書き加えます。クォートのクォートってことですか。次に、”コマンド” のあと「 & 変数」と繋げます。コマンドの外で繋げるんですか。

上の実例を当てはめるとこうなります。

tell application "Terminal"
	activate
	set thePath to quoted form of "/Volumes/Drobo 5D/Art/"
	do script with command "ls -l" & thePath
end tell

パスを一旦変数に収めてから配置するということはこれまでもやってきました。でも駄目でした。その答えは、変数に収めるときに「 to quoted form of」を宣言することと、コマンドに & で繋げるということだったようです。こうするとエスケープ処理も不要です。

これは大きな発見でした。マイコードリファレンス兼発射装置データベースファイル 始め、いろいろなFMファイルも更新しなければ。

クォーテーション指定で変数に収めたものが実際にどう出力されてるかというと、こうなってるんですねえ。

"'/Volumes/Drobo 5D/Art/'"

「素人が手を出すんじゃねえ」と脅されて逃げていたスペースを含むパス問題、ついに解決して、今後使える機能となりました。つまり、今日からあなたも私も、もはや素人ではなくなったのですね。

毛の生えた素人になりました。

AppleのDocumentation Archive: Mac Automation Scripting Guide > Calling Command-Line Tools

 

Penguin icon ※ この話には続きがあります。

【 続き 】

少し複雑なコマンドでやさぐれてそして解決

毛が生えたと喜んでる場合ではありませんでした。

前回の記事 stat で日付をゲット – ステイタスコマンド で書いたコマンドが上手に送れません。

stat -f "%N%T+++%B+++%m" パス/* | pbcopy

これです。これが送れません。具体例で書きましょうか。

stat -f "%N%T+++%B+++%m" /Library/Application Support/* | pbcopy

コマンドがあって、オプションがあって、フォーマットのテンプレがあって、パスがあって、パスの終わりはワイルドカードで、最後に pbcopy を繋げています。

これ、どうしましょ。

stat のコマンドとテンプレ部分はこうだと思うんです。

do shell script "stat -f " & "%N%T+++%B+++%m"

最後の pbcopy はこうです。

& " | pbcopy "

これらは問題ありません。問題はパスの部分ですよ。

パスの終わりにワイルドカードがくっついてます。set thePath to quoted form of “パス/” のどこにワイルドカードの米印をくっつけるんでしょうか。こうでしょうか。

"/Library/Application Support/*"

これでは駄目ですね。

"/Library/Application Support/" *

こんなわけないし。

"/Library/Application Support/" & "*"

駄目ですねえ。

変数じゃなく、do script のほうに書くんでしょうか。

do script "stat " & "%N%T %B" & thePath & "*" & " | pbcopy"

これも駄目でした。

& thePath * & " | pbcopy"

当然こんなのでは成立すらしないし。そうだ pbcopy のところにくっつけようか。

& "* | pbcopy"

一瞬「これか!」と思ったけど駄目。

どこに * をくっつけてもエラーになるか、そうでなければワイルドカードが効かずフォルダの情報を持ってくるだけです。

あれこれ数時間格闘し、やはり毛の生えた程度の素人に do script は無理であったかと痛感し、やさぐれて不貞寝しました。

詐欺師になって偽物の同窓生を演じ、知らない人を懐かしんでいる夢を見て起きたら少し世界が変わっていました。

デジタルデカ登場

おいしい水出しコーヒーとたばこを立て続けに呑むデジタルデカに啓示が下ったのです。
「おいお前、初期段階で犯人を見落としとるよ」
はて何のことかとひるむデジタルデカ。

啓示の7分後にすべてを解決したのですが、皆様お気づきでしょうか。真犯人は序盤で登場し立ち去っています。

捜査と推理の基本は、確証なく思い込まない事と、地道な積み上げです。そのどちらもが欠けていました。

そもそも間違っている

送りたいコマンドはこれでした。

stat -f “%N%T+++%B+++%m” /Library/Application Support/* | pbcopy

直後にこう書いています。

stat のコマンドとテンプレ部分はこうだと思うんです。

do shell script "stat -f " & "%N%T+++%B+++%m"

(略)

これらは問題ありません。問題はパスの部分ですよ。

愚か者め。ここですでに間違っておるわ。問題ありありです。正解はこうなんです。

do shell script "stat -f '%N%T+++%B+++%m' "

テンプレ含めてちゃんとコマンドとして括り、ダブルクォーテーションだったテンプレ部分をシングルで括り直すのが正しい書き方でした。

ここで間違ってるんだから、パスの変数をどうしようが全部エラーになって当たり前です。

それに気づいたデジタルデカが変数に収めるパスを再度試していきますと、あっさり答えに出会いました。

正解はこうでした。

"/Library/Application Support/" & "*"

すでに試していて「エラーだな。失敗だな」となっていたやつです。これで合ってました。

さらに、こっちでもOKでした。これも合ってた。

do shell script "stat -f '%B' " & thePath & "*"

コマンド部分を間違ったまま変数作りと格闘してやさぐれてた数時間を返せっ。

問題はパスの部分ですよ。

問題はパスの部分になんかなくて、コマンドの部分でした。

まとめまして、通しで書くとこうです。

set thePath to quoted form of "/Library/Application Support/" & "*"
 do shell script "stat -f '%N%T %B' " & thePath & " | pbcopy

あるいはこっちでも。

set thePath to quoted form of "/Library/Application Support/"
 do shell script "stat -f '%N%T %B' " & thePath & "*" & " | pbcopy

 

Digital Boo Pennguin Icon ふたつのことを試すとき、ひとつひとつをシンプルに。