web-dev-qa-db-fra.com

Comment vérifier dans AppleScript si une application est en cours d'exécution, sans la lancer - via l'utilitaire osascript

Considérez le AppleScript suivant:

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

Le problème: lorsque j'exécute cette opération via l'utilitaire de ligne de commande osascript, si Safari n'est pas en cours d'exécution, il est lancé et le script signale «En cours d'exécution». Ce n'est pas le comportement que je désire ou auquel je m'attendrais. Notez que cela fonctionne comme souhaité/attendu lorsqu’il est exécuté dans l’éditeur AppleScript.

S'agit-il d'un bogue osascript/d'un problème connu? Ou est-ce en quelque sorte le comportement voulu pour les raisons qui me manquent? Quelqu'un peut-il le faire fonctionner comme souhaité? (BTW, je suis sous OSX 10.7.5; je ne vois pas comment obtenir osascript pour signaler un numéro de version).

Si vous commentez les lignes tell/end tell, elles se comporteront comme je le pensais: si Safari n'est pas en cours d'exécution, il ne le lancera pas et affichera "Pas en cours d'exécution". Donc il me sembleque la tell me semble être à l’origine du lancement de Safari, mais elle n’a pas besoin d’être exécutée, elle est simplement présente dans le script ...? Pendant un moment, je me suis demandé si c'était peut-être juste comment tell est supposé fonctionner, mais étant donné que ne fonctionne pasde cette façon dans l'éditeur AppleScript, je suppose que non ...

En fait, voici une autre version, madder, avec un comportement similaire:

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

Cela lance toujours toujours Safari, même si tell se trouve à l'intérieur d'un bloc if false après l'instruction de retour! (Mais encore une fois, c'est bien dans l'éditeur AppleScript.)

BTW, ce comportement n'est pas limité à Safari, mais il n'est pas non plus universel:

  • Les applications concernées incluent: Safari, TextEdit, iPhoto, AppleScript Editor, iTerm, ...
  • Les applications non concernées incluent: Google Chrome, iTunes, Aperçu, Mail, Terminal, Carnet d'adresses, Echofon, ...

Alors, est-ce que quelqu'un a une idée sur la façon dont je pourrais résoudre ce problème? Est-ce un bogue osascript? Ou est-ce que je manque quelque chose à propos de la sémantique d'AppleScript?

Pour le contexte: j'essaie d'écrire un script (à intégrer/appelé à partir d'un python) qui interroge les navigateurs ouverts sur les URL des onglets qu'ils ont ouverts; Tout fonctionne très bien saufqui lance toujours Safari, qu'il soit ouvert ou non. J'ai résumé ce comportement indésirable au simple cas de test présenté ci-dessus. Je ne connais aucun moyen de Exécutez ce script à partir de python sans utiliser osascript, à l'exception de appscript , que je ne souhaite pas utiliser car il n'est plus développé/pris en charge/recommandé .

Merci beaucoup pour toutes les contributions/idées!

41
gimboland

Je suppose que la raison en est que chaque fois que vous appelez le script à partir de la ligne de commande avec osascript, le script est en cours de compilation.

Le fait de compiler sur une application tell aura toujours le lancement de l’application.

L'appel du script à partir de la ligne de commande avec osascript à partir d'un fichier pré-compilé, c'est-à-dire . scpt ne provoque pas ce problème, car il n'y a pas de compilation à effectuer.

Mais l'appeler à partir d'un fichier texte brut (.txt, .sh) permettra à l'application de se lancer.

Si vous ne voulez pas utiliser un fichier .scpt et un fichier texte brut, vous pouvez essayer l'astuce consistant à mettre une commande run script dans le script 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
    run script "tell application \"Safari\" 

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

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

Le script dans exécuter le script est uniquement compilé en cas de besoin. Vous devrez échapper aux caractères tels que les guillemets, comme dans mon exemple.

Ce sera plus facile si vous écrivez d'abord le script dans un document normal AppleScript et le compilez pour vérifier les erreurs.

Puis copiez-le dans le fichier texte brut.


METTRE À JOUR **

La méthode que j'ai utilisée ci-dessus est issue d'un vieux script que j'avais utilisé pour résoudre ce problème un certain temps avant de répondre ici. 

La réponse fonctionne et n'essaie pas d'être élégante. ;-)

J'aime réellement user1804762 méthode ci-dessous. Comme cela fonctionne, mais que la réponse n’est pas assez claire, je vais vous donner un exemple d’utilisation.

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

Ce script peut être exécuté à partir de la ligne de commande avec osascript

exemple:

osascript /Users/USERNAME/Desktop/foo.scpt

Notez que le script est enregistré en tant que script compilé. Cela fonctionnera bien et vous pourrez également l'enregistrer et l'utiliser en tant que script en texte brut.

c'est à dire.

osascript /Users/USERNAME/Desktop/foo.applescript

47
markhunte

Quelques infos:

"Modèle objet d'application amélioré":

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

Vous pouvez aussi le faire de cette façon:

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

Vous pouvez aussi faire ceci:

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

Et pour compléter le voyage:

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

C'était le "modèle objet d'application amélioré". Si une application est toujours lancée (par exemple, la première fois que vous compilez et exécutez le script), je suppose que c'est parce qu'AS doit obtenir des informations de l'application qu'elle n'a pas trouvées dans le dictionnaire (ou quelque chose comme ça ...? ).

45
user1804762

OK, je sais que cette question est vraiment ancienne, mais je suis tombé sur cette question à la recherche d’un problème différent et j’ai dû réfléchir à la complexité de certaines de ces réponses.

Le code simple pour réaliser ce que vous voulez (ed) est:

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

Sur les systèmes plus anciens, la syntaxe utilisée doit être:

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

Un de ceux-ci devrait certainement fonctionner pour vous, chercheur intrépide de solutions Applescript pour l'action uniquement lorsqu'une application est en cours d'exécution.


Oh! Astuce bonus: Et si vous n'êtes pas sûr du nom exact du processus de l'application (c'est habituellement mais pas toujours le nom de l'application), avant de coder le script final exécuté

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

Et trouvez le nom du processus de votre application dans les résultats.

Voici une capture d'écran de l'exécution de cette commande. (Notez les zillions d'instances Google Chrome Helper. Merci Google!)

enter image description here

HTH!

7
dashard

Toutes les réponses précédemment faites souffrent du même problème, cependant:

Ils recherchent l'application par son nom. Toutefois, l'utilisateur peut renommer l'application. Le script croit alors que l'application ne s'exécute pas, alors qu'elle le fait.

Pour vérifier correctement qu'une application est en cours d'exécution, vous devez la trouver à l'aide de son ID d'ensemble, que l'utilisateur ne peut pas modifier.

L'ID de paquet peut être demandé avec cette commande, par exemple:

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

Pour vérifier si une application avec un ID de bundle particulier est en cours d'exécution, utilisez ce code:

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

En outre, voici un exemple pour vérifier si une application est en cours d'exécution, puis la quitter, puis la relancer, en veillant à ce que la même application soit exécutée auparavant, et qu'aucune autre copie ne soit présente:

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
Thomas Tempelmann
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

Ceci retourne {"Finder", "JavaAppLauncher", "firefox", "Microsoft Word", "iTunes", "AppleScript Editor"} pour moi

J'espère que cela t'aides

1
Kamin Pallaghy

J'ai eu le même problème que décrit ici en essayant de configurer un AppleScript (déclenché par un geste BetterTouchTool) qui lit/met en pause VLC ou iTunes, mais seulement iTunes si VLC n'est pas en cours d'exécution (à cause de mon flux de travail) et, bien entendu, uniquement VLC c'est en cours d'exécution. (J'utilise le déclencheur automatique de pause/lecture pour iTunes dans les paramètres de VLC, pour le lancement et la fermeture de l'application.)

VLC a toujours été lancé lors de la première utilisation du BetterTouchTool-trigger après chaque relance de BTT, car le cache du dictionnaire est supprimé à ce moment-là et le gestionnaire AppleScript doit lancer chaque application scriptée si un tell le vise pour pouvoir l'appeler. dictionnaire.

Je n'ai rien trouvé qui évite cela nulle part; il y a eu quelques tentatives, mais aucune n'a fonctionné pour moi car l'appel du dictionnaire par le gestionnaire de script ne peut en aucun cas être influencé. Je suis venu avec cette solution de contournement sale:

  • Créez un fichier AppleScript séparé contenant uniquement la ligne qui inclut tell pour VLC
  • Enregistrez-le à un endroit où il ne vous importunera pas
  • Remplacez la ligne contenant tell dans le script AppleScript d'origine par une ligne exécutant ce script.

Cela conduira à la première compilation du script n'appelant pas l'application (VLC, dans mon cas) directement, mais uniquement le script, ce qui signifie que l'application n'aura pas besoin de se lancer.

VLC devra être lancé une fois ce fichier séparé appelé, mais si vous appelez ce fichier pour indiquer quelque chose à VLC, vous aurez VLC déjà ouvert (ou vous voudrez l'ouvrir).

Le script AppleScript que j'appelle via mon BetterTouchTool-trigger (un tap spécifique sur le trackpad, dans mon cas) ressemble à ceci:

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

se termine si si l'application "VLC" est en cours d'exécution, alors exécuter le script "/Users/jannis/bin/PlayVLC.scpt"end if

Le fichier AppleScript séparé ("PLayVLC.scpt, enregistré dans un dossier appelé" bin "dans mon dossier utilisateur que j'ai créé manuellement il y a bien longtemps à de telles fins) est le suivant:

tell application "VLC" to play

Si vous ouvrez ce script manuellement, il lancera bien sûr également VLC. Espérons que cela ne sera pas nécessaire souvent, ni jamais.

En fait, je ne sais vraiment pas si cela crée des problèmes plus profonds que je ne connais pas car je ne suis pas un codeur professionnel; Si oui, s'il vous plaît informez-moi. J'espère que cela aide n'importe qui!

0
jatenk