web-dev-qa-db-ja.com

osascriptユーティリティを使用して、アプリを起動せずに実行している場合にAppleScriptをチェックインする方法

次のAppleScriptを検討してください。

on is_running(appName)
    tell application "System Events" to (name of processes) contains appName
end is_running

set safRunning to is_running("Safari")
if safRunning then
    tell application "Safari"
      -- Stuff I only want executed if Safari is running goes here.
    end tell
    return "Running"
else
    return "Not running"
end if

問題:osascriptコマンドラインユーティリティを使用してこれを実行すると、Safariが実行されていない場合、Safariが起動し、スクリプトが「実行中」と報告します。これは、私が望んでいる、または期待する動作ではありません。 AppleScript Editor内で実行すると、期待どおりに動作することに注意してください。

これはosascriptバグ/既知の問題ですか?それとも私が行方不明の理由で何らかの形で意図された動作ですか?誰でも希望どおりに動作させることができますか? (ところで、OSX 10.7.5を実行しています。osascriptを取得してバージョン番号を報告する方法がわかりません)。

tell/end tell行をコメントアウトすると、期待どおりに動作します。Safariが実行されていない場合、Safariは起動せず、「Not running」と出力されます。 seemsは、tellがSafariを起動する原因になっているように思えますが、実際に実行する必要はなく、スクリプトに存在するだけです...?しばらくの間、これは単にtellがどのように機能するかを疑問に思っていましたが、AppleScript Editorではdoes n'tのように機能するので、そうではないと思います...

実際、同様の動作をする別のバージョンのhereがあります。

on is_running(appName)
    tell application "System Events" to (name of processes) contains appName
end is_running

set safRunning to is_running("Safari")
return safRunning
if false then
    tell application "Safari"
    end tell
end if

tellがreturnステートメントの後のif falseブロック内にある場合でも、これは常にSafariを起動します! (ただし、これはAppleScript Editorでは問題ありません。)

ところで、この動作はSafariに限定されませんが、普遍的でもありません。

  • 影響を受けるアプリには、Safari、TextEdit、iPhoto、AppleScript Editor、iTermなどがあります。
  • 影響を受けないアプリには、Google Chrome、iTunes、プレビュー、メール、ターミナル、アドレス帳、Echofonなどがあります。

だから、私はこれをどのように修正するかルーティングするかについてアイデアを持っていますか? osascriptのバグですか?または、AppleScriptのセマンティクスについて何かが欠けていますか?

コンテキストの場合:開いているブラウザのタブのURLを開いているブラウザに照会するスクリプト(埋め込みまたはPythonから呼び出される)を作成しようとしています。すべて正常に動作しています除く開いているかどうかにかかわらず、常にSafariを起動します。この望ましくない動作を、上記の簡単なテストケースに要約しました。 osascriptを使用せずにpythonからこのスクリプトを実行する方法は、 appscript 以外は知りません。 開発/サポート/推奨されなくなった であるため使用します。

すべての入力/洞察に感謝します!

43
gimboland

これを取得している理由は、osascriptを使用してコマンドラインからスクリプトを呼び出すたびに、スクリプトがコンパイルされているためと思われます。

tell applicationでコンパイルする行為により、アプリが起動します。

プリコンパイルされたファイルからのosascriptを使用してコマンドラインからスクリプトを呼び出します。つまり、.scptは、実行されるコンパイルがないため、この動作を引き起こしません。

ただし、プレーンテキスト(.txt、.sh)ファイルから呼び出すと、アプリが起動します。

.scptファイルを使用したくない場合、およびプレーンテキストファイルを使用する場合は、AppleScriptにrun scriptコマンドを挿入するトリックを試すことができます。

on is_running(appName)
    tell application "System Events" to (name of processes) contains appName
end is_running

set safRunning to is_running("Safari")
if safRunning then
    run script "tell application \"Safari\" 

open location \"http://google.com\"

    end tell"
    return "Running"
else
    return "Not running"
end if

run scriptのスクリプトは、必要な場合にのみコンパイルされます。私の例のように引用符のような文字をエスケープする必要があります。

最初に通常のapplescriptドキュメントにスクリプトを記述し、コンパイルしてエラーをチェックする方が簡単です。

次に、それをプレーンテキストファイルにコピーします。


[〜#〜] update [〜#〜] **

上記で使用した方法は、ここで答える前にこの問題を解決するために使用していた古いスクリプトからでした。

答えは機能し、エレガントにしようとするものではありません。 ;-)

私は実際にser1804762メソッドが好きです。それは機能しますが、答えが十分に明確ではないと感じているため、使用例を示します。

set appName to "Safari"

if application appName is running then

    tell application id (id of application appName)

        open location "http://google.com"
    end tell
    return "Running"
else
    return "Not running"
end if

このスクリプトは、コマンドラインからosascriptを使用して実行できます

例:

osascript /Users/USERNAME/Desktop/foo.scpt

スクリプトがコンパイル済みスクリプトとして保存されていることに注意してください。これは問題なく動作し、プレーンテキストスクリプトとして保存して使用することもできます。

つまり.

osascript /Users/USERNAME/Desktop/foo.applescript

48
markhunte

いくつかの情報:

「強化されたアプリケーションオブジェクトモデル」:

tell application "iTunes"
    if it is running then
      pause
    end if
end tell

そのようにすることもできます:

if application "iTunes" is running then
    tell application "iTunes" to quit
end if

これも行うことができます:

get name of application "iTunes"
get version of application "iTunes"

そして旅を完了するには:

get id of application "TextEdit" --> "com.Apple.TextEdit"
tell application id "com.Apple.TextEdit"
    make new document
end tell

それが「拡張アプリケーションオブジェクトモデル」でした。アプリがまだ起動する場合(たとえば、最初にスクリプトをコンパイルして実行する場合)は、ASがアプリが辞書にない情報(またはそのようなもの...? )。

48
user1804762

わかりました、この質問は本当に古いことを知っていますが、別の問題を探すためにつまずいて、これらの応答のいくつかがどれほど複雑であるかを検討しなければなりませんでした。

目的を達成するための簡単なコードは次のとおりです。

tell application "System Events"
  if application process "Safari" exists then
    -- do stuff you want to do only if Safari exists
  end if
end tell

古いシステムでは、構文usedは次のようになります。

tell application "System Events"
  if exists of application process "Safari" is true then
    -- do stuff you want to do only if Safari exists
  end if
end tell

これらの1つは間違いなくあなたのために働くはずです、Applescriptソリューションの勇敢な検索者は、アプリが実行されているときのみアクションを実行します。


Oh!ボーナスヒント:そして、アプリケーションプロセス名が正確にわからない場合(通常はですが、alwaysアプリ名ではありません)、最終的なスクリプトの実行をコーディングする前に…

tell application "System Events"
   get every application process
end tell

結果でアプリのプロセス名を見つけます。

以下は、そのコマンドを実行する画面の一部です。 (無数のGoogle Chrome Helperインスタンス。ありがとうGoogle!)

enter image description here

HTH!

7
dashard

ただし、以前に行われたすべての回答には同じ問題があります。

名前でアプリを探します。ただし、ユーザーがアプリの名前を変更すると、実際にはアプリは実行されますが、スクリプトはアプリが実行されないと判断します。

実行中のアプリを適切に確認するには、ユーザーが変更できないバンドルIDで見つける必要があります。

バンドルIDは、たとえば次のコマンドで照会できます。

tell application "System Events"
    get bundle identifier of application process "Safari"
end tell

特定のバンドルIDを持つアプリが実行されているかどうかを確認するには、次のコードを使用します。

tell application "System Events"
    set ids to bundle identifier of every application process
    if ids contains "com.Apple.safari" then
        return "Running"
    else
        return "Not running"
    end if
end tell

さらに、アプリが実行されているかどうかを確認し、終了してから再起動し、以前実行されていたものとまったく同じアプリが再起動され、他のコピーも存在しないことを確認する例を次に示します:

set bundleID to "com.Apple.safari"
set apps to runningApps(bundleID)
set appCount to length of apps
if appCount is not 0 then
    quit application id bundleID
    repeat while length of runningApps(bundleID) = appCount
        -- wait for the app to quit
    end repeat
    open first item of apps
end if

on runningApps(bundleID)
    -- The try block is to catch the rare case of having more than one
    -- copy of an app running at the same time. Unfortunately, in that
    -- case this code will not run as expected, because we don't get the
    -- correct list of multiple items back then. But at least the script
    -- will not crash from it but handle it gracefully.
    tell application "System Events"
        try
            return application file of (every application process whose bundle identifier = bundleID)
        end try
    end tell
    return {}
end runningApps
1
tell application "Finder"
    set applicationsnames to get the name of every process whose visible is true
end tell

set appName to "Safari"

if applicationsnames does not contain appName then
    say (appName & " is not running")
    --add here what you want to happen

end if
return applicationsnames

これは私のために{"Finder", "JavaAppLauncher", "firefox", "Microsoft Word", "iTunes", "AppleScript Editor"}を返しています

お役に立てれば

1
Kamin Pallaghy

VLCまたはiTunesを再生/一時停止するAppleScript(BetterTouchToolジェスチャによってトリガーされる)を設定しようとして、ここで説明したのと同じ問題がありましたが、VLCが実行されていない場合はiTunesのみ(私のワークフローのため)、当然ながらVLCのみが実行中です。 (VLCの設定でiTunesの自動一時停止/再生トリガーを使用して、アプリを起動および終了します。)

VLCは、BTTを再起動するたびにBetterTouchToolトリガーを最初に使用したときに常に起動され、その時点で辞書キャッシュが削除され、AppleScriptハンドラーは、スクリプトを呼び出すためにテルを目的とする場合、すべてのスクリプトアプリケーションを起動する必要があります辞書。

これを回避するものはどこにも見つかりませんでした。いくつかの試みがありましたが、スクリプトハンドラーによる辞書呼び出しは私たちが影響を与えることができるものではないため、私にとってはうまくいきませんでした。私はこの汚い回避策を思いつきました:

  • VLCのtellを含む行のみを含む別のAppleScriptファイルを作成します
  • 迷惑にならない場所に保存してください
  • 元のAppleScriptのtellを含む行を、そのスクリプトを実行する行に置き換えます

これにより、アプリケーション(私の場合はVLC)を直接呼び出すのではなく、スクリプトのみを呼び出すスクリプトの最初のコンパイルが行われます。つまり、アプリケーションを起動する必要はありません。

その個別のファイルが呼び出されたらVLCを起動する必要がありますが、VLCに何かを伝えるためにそのファイルを呼び出すと、とにかくVLCが既に開かれている(または開かれる)ことになります。

BetterTouchToolトリガー(この場合はトラックパッドの特定のタップ)を介して呼び出すAppleScriptは、次のようになります。

if application "iTunes" is running and not application "VLC" is running then
tell application "iTunes" to playpause

アプリケーション「VLC」が実行されている場合は終了し、スクリプト「/Users/jannis/bin/PlayVLC.scpt」を実行します

別のAppleScriptファイル( "PLayVLC.scpt、このような目的のために以前に手動で作成したユーザーフォルダーの" bin "というフォルダーに保存)は、これだけです。

tell application "VLC" to play

そのスクリプトを手動で開くと、もちろんVLCも起動します。しかし、願わくば、それは頻繁に、またはこれまで必要ではないでしょう。

私はプロのコーダーではないので、これが私が知らないより深い問題を引き起こすかどうかは、実際にはわかりません。もしそうなら、私に通知してください。これが誰にも役立つことを願っています!

0
jatenk