it-swarm.com.de

So überprüfen Sie in AppleScript, ob eine App ausgeführt wird, ohne sie zu starten - über das Hilfsprogramm osascript

Betrachten Sie das folgende 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

Das Problem: Wenn ich dies über das Befehlszeilendienstprogramm osascript ausführe, wird Safari gestartet, wenn es nicht ausgeführt wird, und das Skript meldet "Wird ausgeführt". Dies ist nicht das Verhalten, das ich wünsche oder erwarten würde. Beachten Sie, dass es wie gewünscht/erwartet funktioniert, wenn es im AppleScript Editor ausgeführt wird.

Ist dies ein osascript Fehler/bekanntes Problem? Oder ist es irgendwie beabsichtigtes Verhalten aus Gründen, die ich vermisse? Kann jemand es wie gewünscht zum Laufen bringen? (Übrigens, ich verwende OSX 10.7.5. Ich kann nicht sehen, wie ich osascript bekomme, um eine Versionsnummer zu melden.).

Wenn Sie die Zeilen tell/end tell auskommentieren, verhält es sich wie erwartet: Wenn Safari nicht ausgeführt wird, wird es nicht gestartet und die Meldung "Not running" wird ausgegeben. Also scheint mir , als würde tell Safari starten, aber es muss nicht wirklich ausgeführt werden, sondern nur im Skript vorhanden sein. .? Für eine Weile habe ich mich gefragt, ob das vielleicht genau so ist, wie tell funktionieren soll, aber da es im AppleScript Editor nicht so funktioniert, denke ich nicht. ..

In der Tat ist hier eine andere, verrückte, Version mit ähnlichem Verhalten:

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

Dadurch wird Safari immer gestartet, obwohl sich tell nach der return-Anweisung in einem if false -Block befindet! (Aber auch dies ist in AppleScript Editor in Ordnung.)

Übrigens ist dieses Verhalten nicht nur auf Safari beschränkt, sondern auch nicht universell:

  • Betroffene Apps sind: Safari, TextEdit, iPhoto, AppleScript Editor, iTerm, ...
  • Zu den nicht betroffenen Apps gehören: Google Chrome, iTunes, Vorschau, Mail, Terminal, Adressbuch, Echofon, ...

Hat jemand eine Idee, wie ich das beheben oder umgehen könnte? Ist es ein osascript Fehler? Oder vermisse ich etwas über die Semantik von AppleScript?

Zum Kontext: Ich versuche, ein Skript zu schreiben (das von einem Python eingebettet/aufgerufen werden soll), das offene Browser nach den URLs aller geöffneten Registerkarten abfragt. Ich habe alles in Ordnung , außer , dass Safari immer gestartet wird, egal ob es geöffnet ist oder nicht. Ich habe dieses unerwünschte Verhalten auf den oben gezeigten einfachen Testfall zurückgeführt. Mir ist keine Möglichkeit bekannt, dieses Skript von python aus auszuführen, ohne osascript zu verwenden, außer appscript , das ich nicht verwenden möchte, weil - es ist nicht mehr entwickelt/unterstützt/empfohlen .

Vielen Dank für alle Inputs/Einsichten!

43
gimboland

Ich vermute, der Grund, warum Sie dies erhalten, ist, dass jedes Mal, wenn Sie das Skript über die Befehlszeile mit osascript aufrufen, das Skript kompiliert wird.

Wenn Sie eine tell-Anwendung kompilieren, wird afaik die App starten.

Das Aufrufen des Skripts über die Befehlszeile mit osascript aus einer vorkompilierten Datei, d. H. .scpt, führt nicht zu diesem Verhalten, da das Kompilieren nicht ausgeführt wird.

Wenn Sie es jedoch aus einer Klartextdatei (.txt, .sh) aufrufen, wird die App gestartet.

Wenn Sie keine .scpt-Datei und keine Nur-Text-Datei verwenden möchten, können Sie den Trick versuchen, den Befehl run script in das Applescript einzufügen.

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

Das Skript im run-Skript wird nur bei Bedarf kompiliert. Sie müssen Zeichen wie Anführungszeichen wie in meinem Beispiel mit Escapezeichen versehen.

Es ist einfacher, wenn Sie das Skript zuerst in ein normales applescript-Dokument schreiben und es zur Fehlerprüfung kompilieren.

Kopieren Sie es dann in die Nur-Text-Datei.


UPDATE **

Die Methode, die ich oben verwendete, war aus einem alten Skript, mit dem ich dieses Problem gelöst hatte, bevor ich hier antwortete. 

Die Antwort funktioniert und versucht nicht, elegant zu sein. ;-)

Ich mag die user1804762 -Methode unten. Wie es funktioniert, fühlt sich die Antwort jedoch nicht klar genug an, deshalb werde ich ein Beispiel dafür geben.

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

Dieses Skript kann von der Befehlszeile aus mit osascript ausgeführt werden.

beispiel:

osascript /Users/USERNAME/Desktop/foo.scpt

Beachten Sie, dass das Skript als kompiliertes Skript gespeichert wird. Dies funktioniert in Ordnung und Sie können es auch als reines Text-Skript speichern und verwenden.

d.h.

osascript /Users/USERNAME/Desktop/foo.applescript

47
markhunte

Einige Infos:

"Erweitertes Anwendungsobjektmodell":

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

Sie können es auch so machen:

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

Sie können dies auch tun:

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

Und um die Reise abzuschließen:

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

Das war das "Enhanced Application Object Model". Wenn eine App noch startet (zum Beispiel, wenn Sie das Skript zum ersten Mal kompilieren und ausführen), gehe ich davon aus, dass AS Informationen aus der App abrufen muss, die nicht im Wörterbuch gefunden wurden (oder ähnliches?). ).

45
user1804762

OK, ich weiß, dass diese Frage wirklich alt ist, aber ich bin auf der Suche nach einem anderen Thema gestolpert und musste nachdenken, wie kompliziert einige dieser Antworten sind.

Der einfache Code, um das zu erreichen, was Sie wollen (ed) ist:

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

Auf älteren Systemen wurde die Syntax als verwendet:

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

Eine davon sollte auf jeden Fall für Sie, den unerschrockenen Sucher von Applescript-Lösungen, nur dann funktionieren, wenn eine App ausgeführt wird.


Oh! Bonus-Tipp: Und wenn Sie nicht sicher sind, wie der Anwendungsprozessname genau ist (es ist normalerweise, aber nicht immer der App-Name), bevor Sie den endgültigen Skriptlauf ausführen…

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

Und finden Sie den Namen Ihres App-Prozesses in den Ergebnissen.

Hier ist ein Bildschirm, der diesen Befehl ausführt. (Beachten Sie die Millionen von Google Chrome Helper -Instanzen. Danke, Google!)

enter image description here

HTH!

7
dashard

Alle zuvor gemachten Antworten leiden jedoch unter dem gleichen Problem:

Sie suchen die App anhand ihres Namens. Der Benutzer kann die App jedoch umbenennen und dann glaubt das Skript, dass die App nicht ausgeführt wird, obwohl dies tatsächlich der Fall ist.

Um ordnungsgemäß nach einer laufenden App zu suchen, sollte diese anhand ihrer Bundle-ID gefunden werden, die der Benutzer nicht ändern kann.

Die Bundle-ID kann beispielsweise mit diesem Befehl abgefragt werden:

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

Verwenden Sie diesen Code, um zu überprüfen, ob eine App mit einer bestimmten Bundle-ID ausgeführt wird:

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

Nachfolgend ein Beispiel, um zu überprüfen, ob eine App ausgeführt wird. Beenden Sie sie und starten Sie sie erneut. Stellen Sie sicher, dass dieselbe App erneut gestartet wird, die zuvor ausgeführt wurde, und keine andere Kopie, die möglicherweise ebenfalls vorhanden ist:

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

Dies gibt {"Finder", "JavaAppLauncher", "firefox", "Microsoft Word", "iTunes", "AppleScript Editor"} für mich zurück

Hoffe das hilft

1
Kamin Pallaghy

Ich hatte das gleiche Problem wie beim Versuch, ein AppleScript einzurichten (das durch eine BetterTouchTool-Geste ausgelöst wird), das VLC oder iTunes abspielt/anhält, aber nur iTunes, wenn VLC (aufgrund meines Workflows) nicht läuft und natürlich nur VLC Es rennt. (Ich verwende den automatischen Pause/Play-Auslöser für iTunes in den VLC-Einstellungen zum Starten und Beenden der App.)

VLC wurde immer bei der ersten Verwendung des BetterTouchTool-Auslösers nach jedem Neustart von BTT gestartet, da der Wörterbuchcache an diesem Punkt gelöscht wird und der AppleScript-Handler jede Skriptanwendung starten muss, wenn ein Tell darauf abzielt, um dessen Aufruf aufzurufen Wörterbuch.

Ich habe nichts gefunden, was dies nirgendwo vermied; Es gab einige Versuche, aber keiner hat für mich funktioniert, da der Wörterbuchaufruf durch den Skript-Handler nichts ist, was wir beeinflussen können. Ich habe mir diesen schmutzigen Workaround ausgedacht:

  • Erstellen Sie eine separate AppleScript-Datei, die nur die Zeile enthält, die den Hinweis für VLC enthält
  • Speichern Sie es an einem Ort, an dem es Sie nicht stört
  • Ersetzen Sie die Zeile mit dem Tell im ursprünglichen AppleScript durch eine Zeile, die das Skript ausführt

Dies führt dazu, dass die erste Kompilierung des Skripts nicht die Anwendung (in meinem Fall VLC) direkt aufruft, sondern nur das Skript. Dies bedeutet, dass die Anwendung nicht gestartet werden muss.

VLC muss gestartet werden, sobald die separate Datei aufgerufen wird. Wenn Sie diese Datei jedoch aufrufen, um VLC etwas mitzuteilen, haben Sie VLC bereits geöffnet (oder möchten es geöffnet haben).

Das AppleScript, das ich über meinen BetterTouchTool-Trigger anrufe (in meinem Fall ein bestimmtes Tippen auf das Trackpad), sieht folgendermaßen aus:

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

end wenn wenn die Anwendung "VLC" ausgeführt wird, dann Skript ausführen "/Users/jannis/bin/PlayVLC.scpt"end if

Die separate AppleScript-Datei ("PLayVLC.scpt, gespeichert in einem Ordner mit dem Namen" bin "in meinem Benutzerordner, den ich zuvor für solche Zwecke manuell erstellt habe) ist Folgendes:

tell application "VLC" to play

Wenn Sie dieses Skript manuell öffnen, wird VLC natürlich auch gestartet. Aber das wird hoffentlich nicht oft oder nie nötig sein.

Ich habe eigentlich keine Ahnung, ob dadurch tiefere Probleme entstehen, die ich nicht kenne, da ich kein Produzent bin. wenn ja, bitte benachrichtigen sie mich. Ich hoffe das hilft jedem!

0
jatenk