Apple Developer Connection
高度な検索
Member Login ログイン | ご入会 ADC連絡先

Technical Note TN2065
AppleScriptのdo shell script

このテクニカルノートでは、AppleScript 1.8に導入されたAppleScriptのdo shell scriptコマンドに関するよくある質問を取り上げます。





このテクニカルノートでは、do shell scriptの使い方に関するよくある質問を取り上げます。Unixのシェルスクリプトで実行できることや書き方については説明しません。それについては、適切なUnixの参考資料を見つけるか、身近にいるエキスパートに相談してください。本稿はQ&A形式で構成されているため、関心のある問題にすぐにスキップすることも、始めから終わりまで通読することもできます。

いくつかの回答で「manページ」に触れていますが、これらはMac OS Xに含まれている参考ドキュメントです(「man」は「manual」の省略)。あるコマンドのmanページを参照するには、「ターミナル」ウインドウを開き、man echoのように、manの後にコマンド名を入力します。

コマンドの発行

Q:シェルコマンドにAppleScript変数を渡すには、どうしたらよいのでしょうか?

A:do shell scriptへのコマンド引数は実際には単なる文字列であるため、AppleScript連結演算子&を使用して実行時に文字列を構成できます。たとえば、変数をコマンドパラメータとして渡すには、次のようにします。

set hostname to "www.apple.com"
do shell script "ping -c1 " & hostname

コマンドによっては、データを標準入力に渡す必要があります。do shell scriptはこれを直接的にはサポートしていませんが、echoとパイプを使って標準入力に見せかけることはできます。

set input to "hello"
do shell script "echo " & input & " | tr a-z A-Z"
-- "HELLO"

一般には、quoted form ofを使用して変数を引用符で囲む必要があります。詳細については、「テキストの扱い」を参照してください。

Q:「ターミナル」では正常に動作するコマンドが、do shell scriptで使おうとすると、「command not found(コマンドが見つかりません)」というエラーが表示されます。どうなっているのでしょうか?

A:2つの可能性があります。1つは、do shell scriptは常に/bin/shを使用してコマンドを解釈し、「ターミナル」が使用するデフォルトのシェルを使用していることです(デフォルトのシェルを見つけるには、「ターミナル」で「echo $SHELL」と入力します)。コマンドによってはシェル間で同じ動作をするものと、そうでないものがあり、動作が異なるコマンドの1つを使用した可能性があります。do shell scriptスクリプトを最初に「ターミナル」で書く場合は、必ずshを使用してください。「bin/sh」と入力すると、shを起動できます。通常のシェルに戻るには、「exit」と入力します。

もう1つは、コマンド名だけを使用した場合、シェルは(PATHとして知られる)ディレクトリのリストを使って、そのコマンドの完全パスを探そうとします。セキュリティと移植性の理由から、do shell scriptは、対話型シェルが読み取るような構成ファイルを無視するため、「ターミナル」でカスタマイズが行われていたとしてもそれは利用されません。このため、単に「ifconfig」とするのではなく、「/sbin/ifconfig」のようにコマンドへの完全パスを使用してください。「ターミナル」で完全パスを調べるにはwhich コマンド名which ifconfigなど)と入力し、do shell scriptが検索する場所のリストを表示するにはdo shell script "echo $PATH"と入力します。

(この回答ではいくつかの詳細に触れていません。関心のある方は「細かい話」を参照してください)。

Q:do shell scriptは、なぜ「ターミナル」とまったく同じように動作しないのですか?

A:2つの理由があります。1つは、スクリプトを、異なるシステムで変更することなく実行できるよう保証するためです。あるユーザのデフォルトシェルやPATHを使ったdo shell scriptは、他のユーザの環境では、おそらく実行が中断してしまいます。もう1つは、do shell scriptはPerlなどの他の言語のシェルエスケープのメカニズムに合わせているためです。

Q:sh以外のシェルでコマンドを実行するには、どうしたらよいのでしょうか?

A:使用するシェルを、コマンドで明示的に指定します。選択したシェルにコマンドを渡す方法は、いくつかあります。コマンドをファイルに書き、次のようにファイルを実行する方法もあります。

do shell script "/bin/tcsh my-command-file-path"

いくつかのシェルは、次のようにパラメータとしてスクリプトを受け付けます

do shell script "/bin/tcsh -c 'my-command'"

また、大部分のシェルは、次のように標準入力からスクリプトを受け付けます。

do shell script "echo my-command | /bin/tcsh"

不明な点については、使用するシェルのドキュメントを参照してください。do shell script文字列の中でコマンドを使う場合は、コマンドを引用符で囲む必要があります。そうしないと、shはコマンドの特殊文字を解釈します。

Q:1つのdo shell scriptで複数のコマンドを使用するには、どうしたらよいのでしょうか?たとえば、cdコマンドであるディレクトリに移動してから何らかの操作を行いたいのですが、あるコマンドから別のコマンドに移るときに、作業ディレクトリが記憶されません。

A:do shell scriptを呼び出すたびに、新しいシェルプロセスが使用されるため、変数や作業ディレクトリの変更などの状態は、ある呼び出しから次の呼び出しに移る際に保存されません。1回の呼び出しで複数のコマンドを実行するには、次のようにセミコロンでコマンドを区切ります。

do shell script "cd ~/Documents; ls"
-- result:"Welcome.txt"

改行(ASCII文字10)を使用しても正しく機能します。

Q:あるコマンドに関する管理者特権を取得するにはどのようにすればよいですか?

A:次のようにadministrator privilegesuser name、およびpasswordのパラメータを使います。

do shell script "command" user name "me" password "mypassword" with administrator privileges

user namepasswordはオプションです。ユーザ名が省略されていると、do shell scriptは現在のユーザであると仮定します。パスワードが省略されていると、do shell scriptは実行時にパスワードを尋ねてきます。いったんスクリプトが正しく認証されると、5分間は認証を再要求されません。Mac OS X 10.4現在、この猶予期間は他のスクリプトやシステムの他の部分は対象となりません。sudo -kを手動で呼び出す必要はありません。

セキュリティ上の理由で、tellで別のアプリケーションを管理者権限のあるdo shell scriptに指定することはできません。コマンドはtellブロックの外側に置くか、tell meブロックの内側に置いてください。

管理者権限があれば、システム中のすべての場所にあるすべてのファイルを変更できることに注意してください。的確なコマンドをいくつか使用するだけで、システムを起動できない状態にしたり、ディスク全体を消去することさえ可能になるため、用心する必要があります。できれば、どうしても必要な場合以外は、管理者権限は使用しないことをお勧めします。システムレベルでの開発を行っている場合を除き、/System内を変更する必要はまずありません。通常は/Libraryの変更で十分です。

注:sudo(8)とwith administrator privilegesの組み合わせは一般には不要であり、セキュリティホールを生み出します。「sudo」は取り除いてください。

警告:Mac OS X 10.4.0および10.4.1では、with administrator privilegesは、実効ユーザIDだけがrootに設定されているコマンドのみ実行します。そのため、実ユーザIDを使ったコマンドでは問題を引き起こす場合があります。たとえば、Perlでは 「taint mode」セキュリティチェックが有効になり、sudo(8)はハングします。問題を回避するには(sudoの使用を単純に取り除けない場合。上記参照)、次のように、実ユーザIDを設定する小さなPerlスクリプトをコマンドの前に置きます。

do shell script "/usr/bin/perl -Ue '$< = $>; system(@ARGV)' my_command" with administrator privileges

Mac OS X 10.4.2では実ユーザIDと実効ユーザIDを設定するため、ここで述べた回避方法は不要ですが、害はありません。

警告:Mac OS X 10.4より前には、with administrator privilegesが複数のコマンドと正しく動作しませんでした。次のように、複数のコマンドをshの単一の呼び出しに変える必要がありました。

set normal_command to "command1; command2"
do shell script "sh -c " & quoted form of normal_command with administrator privileges

Mac OS X 10.4現在、前述の「複数のコマンドを使用するには、どうしたらよいのでしょうか?」で述べたように、with administrator privilegesは複数のコマンドとともに使用できるようになりました。回避策は不要です。

Q:コマンドはどのくらい長くできますか?最大文字数はどれくらいですか?

A:この質問に対する正確な回答はありません(理由については、「細かい話」を参照)。ただし、概算の回答として、最大約262,000文字までを1つのコマンドとして作成できます。技術的にいえば、1文字あたり1バイトと仮定すると、262,000バイトまでです。非ASCII文字は1文字あたり少なくとも2バイトを使用します。詳細については、「テキストの扱い」を参照してください。

注:以前、この制限はもっと小さく、Mac OS X 10.2では約65,000バイトでした。シェルコマンドsysctl kern.argmaxは、現在の制限をバイト単位で示します。

この制限を超えると、do shell scriptがタイプ255のエラーを返します。この制限を超えるのは、コマンドにインラインデータを渡そとしているケースがほとんどです。インラインデータを渡すのではなく、ファイルにデータを書き込み、ファイルから読み取ることを検討してください。

先頭に戻る

結果の取得

Q:do shell scriptはどのようにして結果を取得するのですか?シェル変数をAppleScriptに返すには、どうしたらよいのでしょうか?

A:シェルコマンドは、標準出力と標準エラー出力という2つの出力ストリームの一方に結果を書き出せます。標準出力は通常の出力に使われ、標準エラー出力はエラーメッセージと診断に使われます。スクリプトが正常に完了したと仮定すると(正常でない場合は次のQ&Aを参照)、結果は標準出力に出力されたテキストに、おそらくいくつかの修正が加えられたものになります。ほとんどのコマンドは結果を標準出力に自動的に出力するため、余計なことは何もする必要はありません。結果が変数にある場合は、echo(ほとんどのシェル)またはprint(PerlやAwkなどの多くの言語)を使用して、その変数を出力する必要があります。たとえば、次のようになります。

リスト1:AppleScript変数のmySlugを日付スラグにyyyy-mm-ddフォーマットで設定します。

set mySlug to do shell script "date +%Y-%m-%d"
-- see the 'date' man page for details on the format string.

リスト2:同じことを実行するPerlスクリプト。

set mySlug to do shell script ¬
    "perl -e 'my (undef, undef, undef, $d, $m, $y) = localtime;
              my $date = sprintf("%4d-%02d-%02d", $y+1900, $m+1, $d);
              print $date'"

デフォルトでは、do shell scriptは結果内の行末をすべてMac形式の復帰改行(\rまたはコード番号13のASCII文字)に変換し、(もしあれば)行末の終了文字を1つ除去します。つまり、「do shell script "echo foo; echo bar"」の結果は、"foo\rbar"のみで、echoが実際に返した"foo\nbar\n"ではないことを意味します。行末を変更しない(without altering line endings)パラメータを追加すると、この2つの動作を両方とも無効にできます。非ASCIIデータの扱いについては、「テキストの扱い」を参照してください。

Q:do shell scriptはエラーをどのように報告するのですか?

A:シェルコマンドはすべて、完了時に整数のステータスを返します。0は成功を表し、それ以外は失敗を表します。0以外のステータスを持つスクリプトがある場合、do shell scriptはステータスがエラー番号であるAppleScriptエラーをスローします(コマンドのmanページに、そのコマンドがどのステータスコードを返せるかが記載されているはずです。大部分のコマンドは、すべてのエラーに単に1を使用します)。スクリプトが標準エラーストリームに対して何かを出力した場合は、そのテキストがAppleScriptのエラーメッセージになります。エラーテキストがない場合、(もしあれば)通常の出力がエラーメッセージとして使用されます。

Q:「ターミナル」でコマンドを実行すると一連の出力が表示されるのですが、do shell script を使用すると、その一部は表示されません。

A:「ターミナル」でコマンドを実行する場合、標準出力と標準エラー出力は両方とも同じ場所に送信されるため、それらを見分けることは困難です。これに対して、do shell scriptは2つのストリームを分離した状態で維持します。標準出力と標準エラー出力を結合したい場合は、次のようにコマンドの後に2>&1を付けます。

do shell script "command 2>&1"

詳細については、manページの「Redirections」を参照してください。

Q:コマンドでどのくらいの出力を返せますか?

A:単一のコマンドで、最大1GBのデータを返すことができます。

先頭に戻る

テキストの扱い

Q:パラメータにスペースや区切り文字(括弧、$、*など)が含まれていると、コマンドが正しく動作しません。

A:シェルは複数のパラメータをスペースで区切り、いくつかの区切り記号には特殊な意味があるため、スペースや区切り記号などを含む文字列を1つのパラメータとしてシェルで処理するには、特別な手順が必要になります。この手順は「クォーティング」と呼ばれ、いくつかの方法がありますが、最も簡単で効果的なのは、文字列のquoted formプロパティを使用する方法です

たとえば、次の(不完全な)ハンドラについて考えてみます。このハンドラは文字列を取得して、ホームディレクトリにある「stuff」というファイルに追加します。

to append_message(s)
    do shell script "echo " & s & " >> ~/stuff"
end append_message

大部分の文字列に対してはうまくいきますが、「$100」などの文字列を使って呼び出すと、この文字列がファイルに追加されるときには、「00」となってしまいます。これは、シェルが“$1”を、値が空の文字列である変数と解釈するためです(shの変数は、先頭にドル記号が付きます)。このスクリプトを修正するには、次のように変更します。

do shell script "echo " & quoted form of s & " >> ~/stuff"

quoted formプロパティにより、フォームの文字列にはその内容に関係なく、シェルによるそれ以上の解釈はなされません。クォーティングの詳細については、shのmanページの「Quoting」を参照してください。

Q:シェルコマンドで二重引用符とバックスラッシュを使う必要があるのですが、AppleScriptで実行すると構文エラーになります。

A:AppleScriptでは、文字列は二重引用符で始まり二重引用符で終わります。文字列の中でリテラルとしての二重引用符を使うには、次のようにバックスラッシュ文字を使って、「エスケープ処理」を行う必要があります。

"a \"quote\" mark"

バックスラッシュには、「次の文字を特別に扱う」という意味があります。このため、リテラルのバックスラッシュを使用するには、次のように2つのバックスラッシュが必要になります。

"a back\\slash"

以上をまとめると、次のようするとうまくいくはずです。

set s to "this is a test."
do shell script "echo " & quoted form of s & " | perl -n -e 'print \"\\U$_\"'"
-- result: "THIS IS A TEST."

スクリプトにはバックスラッシュが追加されていますが、Perlの-eオプションに渡される実際の文字列は、次のようになります。

print "\U$_"

Q:シェルスクリプトが二重引用符やバックスラッシュを返すときには常に、その先頭に余分なバックスラッシュが付いています。

A:結果ウインドウでは、スクリプトにペーストしてそのままコンパイルできるように、結果が「ソース」形式で表示されます。つまり、文字列の結果は引用符で囲まれ、二重引用符やバックスラッシュなどの特殊文字は前述のようにエスケープ処理されるということです。追加されたバックスラッシュは、実際には文字列の一部ではなく、単に表示されているだけです。その文字列をdisplay dialogに渡したり、ファイルに書き込むと、余分なバックスラッシュは表示されません。

Q:do shell scriptは、非ASCIIテキスト(アクセント記号付き文字や日本語など)をどのように扱いますか?

A:AppleScriptの観点からすると、do shell scriptはUnicodeテキストを受け付け、生成します。do shell scriptはUTF-8を使用して、コマンドをシェルに渡し、出力を解釈します。コマンドが有効なUTF-8でなバイトを生成すると、do shell scriptはシステムのプライマリエンコードを使って解釈します。

大部分のシェルコマンドは、UnicodeとUTF-8を完全に無視することを考慮してください。ASCII文字に関しては、UTF-8とASCIIは類似しています。たとえば、「A」はASCIIでもUTF-8でも16進数の0x41です。しかし、非ASCII文字はバイトの並びとして表されます。ただしシェルコマンドに関する限り、1バイトは1文字に相当し、シェルコマンドはASCII範囲外に解釈しようとすることはありません。このことは、シェルコマンドではUTF-8シーケンスが保持され、正確にバイト対バイトの照合が行われることを意味します。たとえば、echo "™"は商標記号を表示し、grep "©"は著作権記号のある行を検索します。ただし、シェルコマンドはUTF-8シーケンスのソート、変更、比較をインテリジェントには処理できません。たとえば、trなどの文字セット照合コマンドや、sedの[]コンストラクトはシーケンスの各バイトを別々に照合し、sortではアクセント記号付き文字の並べ替え順序が不正確で、grep -ifind -inameは「é」と「É」の照合を行いません。Perlはその注目すべき例外です。詳細については、「perlunicode」のmanページを参照してください。

注:AppleScript 1.8.3より前には、do shell scriptはプライマリシステムエンコーディングを使用して入出力を解釈していたので、名前に非ASCII文字のあるファイルを処理するのはきわめて困難でした。

Mac OS X 10.4より前では、有効なUTF-8でない出力は「can’t make some data into the expected type(いくつかのデータを期待されている種類に変換できない)」エラーを生成します。解決策としては、出力をファイルに書き出し、AppleScriptのreadコマンドを使うか、visを通じてパイプ処理を行って読み取る方法があります。10.4以降では、有効なUTF-8でない出力は、プライマリシステムエンコーディングを使用して解釈されます。

Q:行末に関してはどのような規則がありますか?

A:Mac OS Xでは、行末には2種類の規則があります。Mac形式(行は復帰、すなわち\rまたはコード番号13のASCII文字で終了)と、UNIX形式(行は改行、すなわち\nまたはコード番号10のASCII文字で終了)です。シェルコマンドは通常、UNIX形式の行末のみを処理するため、Mac形式のテキストを渡すと、そのままでは使用できない結果が得られます。たとえば、grepでは入力全体には1行しかないとみなされるため、一致は多くても1つになります。

データがAppleScriptのものであれば、行末を変換するか、先頭位置に改行を生成することができます。改行は、"\n"かコード番号10のASCII文字で生成されます。データがファイルからのものである場合は、trを使ってシェルスクリプトで改行コードを変換できます。たとえば、次の例ではプレーンテキストファイルで"something"が含まれる行が検索されます(「quoted form of POSIX path of f」については、「ファイルの扱い」で説明します)。

set f to choose file
do shell script "tr '\\r' '\\n' > " & quoted form of POSIX path of f & " | grep something"

AppleScript自体は行末の種類を区別しません。stringオブジェクトとUnicode textオブジェクトのparagraphエレメントは、Mac、UNIX、Windows形式の行末を同じものと見なします。全般的に、UNIX 形式の行を取得するのにテキスト項目区切り文字(text item delimiters)を使う必要はありません。paragraph nevery paragraphは適切に動作します(ただし、UNIX形式の行末だけを考慮する場合は、text item delimiters を使うのが適切な解決策です。また、AppleScript 1.9.1より以前では、復帰とUnicodeのパラグラフ区切り文字をパラグラフの区切りと見なしていたのは、Unicode textオブジェクトのみです)。

先頭に戻る

ファイルの扱い

Q:AppleScriptのfileオブジェクトまたはaliasオブジェクトを取得した後、これをシェルコマンドに渡すには、どのようにすればよいですか?

A:シェルは、POSIXパス名、すなわちパスの要素がスラッシュで区切られた文字列を使ってファイルを指定します(たとえば、/folder1/folder2/file)。AppleScriptのfileオブジェクトやaliasオブジェクトのPOSIXパス名を取得するには、POSIX pathプロパティを使います(ただし、次のQ&Aを参照してください)。次に例を示します。

POSIX path of file "HD:Users:me:Documents:Welcome.txt"
-- result:"/Users/me/Documents/Welcome.txt"

たとえば、シェルコマンドが結果としてPOSIXパスを返す場合は、POSIX fileを使用するもう1つの方法があります。パス名の付いたPOSIX fileは、通常のfileオブジェクトとして評価され、他のAppleScriptコマンドに渡せます。たとえば、次のようになります。

set p to do shell script "echo ~"
POSIX file p
-- result:file "HD:Users:me:"

Q:ファイル名に、スペース、括弧、$、*などの文字が含まれていると、POSIX pathが正しく動作しません。

A:これはクォーティングの特殊ケースです。シェルがすべての区切り文字をリテラルとして解釈できるようにするには、パスを引用符で囲む必要があります。これを行うには、パスのquoted formを使います。次の例は、名前に関係なく、どのようなファイルにも正しく動作します。

choose file
do shell script "ls -l " & quoted form of the POSIX path of the result
-- result:"-rw-r--r-- 1 me unknown 1 Oct 25 17:48 Look! a file!"

Q:POSIX pathがすべてを引用符で囲まないのはなぜですか?

A:2つの理由があります。第1に、POSIX pathにはシェルパラメータとまったく関係のない使用法があり、そのようなケースではパスを引用符で囲むことは適切ではありません。第2に、quoted formはファイルパス以外のものに対しても効果があります。このため、POSIX pathはすべてを引用符で囲みません。

先頭に戻る

その他の問題点

Q:ftpやtelnetなどの対話型ツールをdo shell scriptで制御するには、どのようにすればよいのですか?

A:簡単にいうと、方法はありません。do shell scriptはコマンドを開始し、コマンドが完了するまでは対話なしで実行するように設計されています。多くのUNIXシェルやPerlのバッククォート演算子によく似ています。

ただし回避策はあります。「ターミナル」のスクリプトを作成して、同じウインドウへ一連のコマンドを送信する方法(ただし、Mac OS X 10.2以降のみ)や、対話型ツールのスクリプティング用のUNIXパッケージ(expectなど)を使う方法があります。また、多くの対話型コマンドには、非対話型の同等のコマンドがあります。たとえば、多くの場合、curlftpの代わりになります。

Q:スクリプトの出力に非常に時間がかかります。結果が出た時点でそれを読むには、どうすればよいですか?

A:これについても方法はありません。do shell scriptはコマンドが完了するまで戻りません。UNIXの言葉でいえば、do shell scriptを使ってパイプを作成することはできません。ただし対処法として、コマンドをバックグラウンドで実行し(次のQ&Aを参照)、出力をファイルに送信して、ファイルが完成したらファイルを読むという方法があります。

Q:バックグラウンドサーバプロセスを開始したい場合、do shell scriptにコマンドの完了を待機させないようにするには、どうすればよいですか?

A:do shell script "command &> file_path &"を使用してください。do shell scriptは、結果なしで直ちに戻り、AppleScriptスクリプトはシェルスクリプトと並行して実行します。シェルスクリプトの出力先はfile_pathになります。出力に関心がない場合は、/dev/nullを使用します。AppleScriptからのバックグラウンドプロセスの取得や操作は、直接的にはサポートされていませんが、次のQ&Aを参照してください。

注:&> file_path> file_path 2>&1と意味的に同等だとすると、標準出力と標準エラーが両方ともfile_pathに出力されることになります。これらを異なる場所に出力する必要がある場合、標準出力は>を使用して、標準エラーは2>を使用して指示します。たとえば、標準エラーをファイルに送信して標準出力を無視するには、次のようにします。

do shell script "command > /dev/null 2> file_path

詳細については、shのmanページで「Redirection」を参照してください。

Q:バックグラウンドプロセスを開始した後、他のシェルコマンドで制御できるようにプロセスIDを取得するには、どうしたらよいのでしょうか?

A:これを行うには、shの機能を利用できます。特別な変数の$!はつい最近実行したバックグラウンドコマンドのIDであるため、次のように、シェルスクリプトで最後のコマンドとしてエコーすることができます。

do shell script "my_command &> /dev/null & echo $!"
-- result: 621
set pid to the result
do shell script "renice +20 -p " & pid
-- change my_command's scheduling priority.
do shell script "kill " & pid
-- my_command is terminated.

Q:topを使おうとすると、「can't get terminal attributes(ターミナル属性を取得できません)」または「error opening terminal: unknown(「ターミナルを開けません:不明」)」というエラーになります。

A:topは、デフォルトのモードではダイナミックに更新される表示画面を作成するために、さまざまな賢い動作をしますが、do shell scriptがカーソルコントロールをサポートしていないのと同じように、出力デバイスがカーソルコントロールをサポートしてない場合は、こうした動作はうまく機能しません。しかし、topにはロギングモードで動作するオプションがあり、do shell scriptのようなファイルに似たデバイスに対しては正常に動作します。代わりにtop -l1を使うか、topのmanページで他のオプションについても参照してください。

この問題は、ターミナルがあることを想定している他のすべてのコマンドにも当てはまります。幸い、その大部分はターミナルを前提としていない比較的単純なコマンドへの、対話型のフロントエンドです。

Q:do shell scriptコマンドのデフォルトの作業ディレクトリはどこですか?

A:do shell scriptは親プロセスの作業ディレクトリを継承します。「スクリプトエディタ」など、ほとんどのアプリケーションでは、デフォルト作業ディレクトリは「/」です。osascriptでは、osascriptを起動した時点におけるシェルの作業ディレクトリになります。特定のディレクトリが必要である場合は、デフォルトの作業ディレクトリを使用しないでください。」作業ディレクトリを特定の場所にする必要がある場合は、自分自身で設定する必要があります。

Q:do shell scriptにどのアプリケーションをtellで指定するかで違いはあるのでしょうか?

A:最も予測可能な結果を得るには、do shell script呼び出しを必ずtellブロックの外側に置くか、tell meを使用します。実際には、osascriptからAppleScriptを実行しないかぎり、これは通常問題にならないし、安全を損ないません(また、別のアプリケーションにdo shell script、または実際にはスクリプティング機能追加を指示すると、そのスクリプティング機能追加が終了するまで、アプリケーションが実行する他の作業はブロックされます。これはたいてい欠点と考えられています)。

問題になるのは、どのアプリケーションに指示するかによって、シェルスクリプトの環境(作業ディレクトリ、環境変数など)が決まることです。ほとんどのアプリケーションは同じ環境ですが、それを当てにするとメンテナンスリスクを負うことになります。osascriptでAppleScriptを実行すると、osascriptを実行したシェルから作業環境が引き継がれますが、それは他のアプリケーションから完全に分離されます。「ターミナル」でshを実行する場合は、次のやり取りを考えてみてください。

$ VAR=something; export VAR
$ osascript -e 'do shell script "echo $VAR"'
something
$ osascript -e 'tell application "Finder" to do shell script "echo $VAR"'
(nothing)

これがどのように機能するかについては、「細かい話」を参照してください。

先頭に戻る

細かい話

このセクションは、シェルスクリプトが機能する仕組みを詳細に知りたい方を対象にしています。スクリプトを正しく機能させたいだけなら、このセクションを読む必要はありません。

Q:実際、do shell scriptはどのシェルを使用するのですか?

A:do shell scriptは必ず/bin/shを呼び出します。しかし、Mac OS Xでは、/bin/shは実際にはshをエミュレートする別のシェルのコピーです。10.2以降では、それはbashであり、それより前はzshでした。

Q:実際、コマンドはどのくらい長くできますか?

A:do shell scriptを呼び出すと新しいshプロセスが作成されるため、新しいプロセスにデータを渡す場合に関するシステムの通常の制限に制約されます。引数(この場合は、コマンドのテキストに加えて約40バイトのオーバーヘッド)と環境変数は、現在262,144バイトであるkern.argmaxより大きくできません。do shell scriptは親の環境を継承するため(次のQ&Aを参照)、コマンドテキストに利用できる正確な容量は呼び出し側の環境によって決まります。実際の問題として、その容量は261,000バイトより若干大きくなりますが、通常の環境設定では大幅に削減される可能性もあります。

Q:シェル環境(環境変数、作業ディレクトリなど)はどこから継承されるのですか?

A:do shell scriptは親プロセスの環境を継承します。do shell scriptがスクリプティング機能追加のように機能するため、do shell script呼び出しの周りにあるtellブロックのアプリケーションが親プロセスです。tellブロックの周りに何もなかったり、tell meを使用している場合は、スクリプトを実行するアプリケーションが親です。

環境は作業ディレクトリ、環境変数、その他の属性に及びます。完全なリストについては、execve(2)のmanページを参照してください。「コマンドの発行」で述べたように、do shell scriptは、「ターミナル」で実行されている対話型シェルが読み取るような構成ファイルを読み取りません。

Finderから起動したアプリケーションは、同じデフォルト環境(作業ディレクトリおよび環境変数HOME、LANG、PATH、USER、SHELL)を取得します(必要であれば、さらに環境変数を定義できます。詳細については、テクニカルQ&A「Setting environment variables for user processes」を参照)。ほとんどのアプリケーションはその環境を変更しませんが、このことに依存するのはメンテナンスのリスクとなります。

osascript(1)は実行されたシェルの環境を継承します。作業ディレクトリはシェルの作業ディレクトリです。シェルで定義された環境変数が、osascript、ひいてはdo shell scriptでも定義されます。たとえば、次のようになります。

$ VAR=something; export VAR
$ osascript -e 'do shell script "echo $VAR"'
something

shでは独自の環境変数をいくつか定義しますが、それが実行されても同じように継承されます。

先頭に戻る

ドキュメント改訂履歴

日付メモ
2006-03-23管理者権限のある他のアプリケーションの指定に関するセキュリティ上の制限を記載。
2005-07-2010.4.2における変更を反映して、「管理者権限」に関する質問を更新。
2005-05-06Mac OS X 10.4 (Tiger)に対応した変更。
2003-01-27新規ドキュメント

掲載日: 2006-03-23




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.