3 votes

Le service Automator script lance TOUJOURS l'application, sans tenir compte des conditionnels.

J'ai écrit un petit service script pour ouvrir une fenêtre de terminal iTerm sur un dossier arbitraire du Finder.

Je veux qu'il vérifie si iTerm est en cours d'exécution, et si c'est le cas, qu'il ouvre la session du terminal dans un nouvel onglet au lieu de l'ouvrir dans un onglet existant.

Le script se présente comme suit :

on run {input, parameters}

set cdPath to "cd " & (quoted form of POSIX path of (input as string))

if application "iTerm" is running then
    display notification "running"
    tell application "iTerm"
        set termWin to (current terminal)
        tell termWin
            launch session "Default"
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell
else
    display notification "not running"
    tell application "iTerm"
        activate
        set termWin2 to (current terminal)
        tell termWin2
            tell the last session
                write text cdPath
            end tell
        end tell
    end tell
end if
return input
end run

Le problème est que lorsque je lance le script en tant que service, il se comporte toujours comme si iTerm était déjà en cours d'exécution (en affichant la notification "en cours d'exécution"), même si iTerm est fermé et très clairement PAS en cours d'exécution.

Mais si je colle le même script à l'éditeur script (en mettant cdPath à un littéral, comme set cdPath to "cd /etc" ) et l'exécuter directement, il fonctionnera correctement, soit en ouvrant une nouvelle instance iTerm, soit en réutilisant une instance existante et en créant un nouvel onglet, et affichera les notifications correspondantes.

Qu'est-ce qui se passe ici ? Pourquoi l'exécution du script en tant que service détecterait l'application comme étant en cours d'exécution quoi qu'il arrive ?

Mise à jour

Si je simplifie le script pour simplement afficher les notifications comme ceci :

on run {input, parameters}

set cdPath to "cd " & (quoted form of POSIX path of (input as string))

  if application "iTerm" is running then
    display notification "running"
  else
    display notification "not running"
  end if
  return input
end run

Il se comportera comme prévu (en affichant 'running' ou 'not running' en conséquence).

Mais si j'ajoute la partie "tell application", elle passera toujours par la branche "running", quoi qu'il arrive.

Par exemple :

on run {input, parameters}

set cdPath to "cd " & (quoted form of POSIX path of (input as string))

  if application "iTerm" is running then
    display notification "running"
  else
    display notification "not running"
    tell application "iTerm"
        activate
    end tell
  end if
  return input
end run

ouvrira toujours iTerm (même si le tell application "iTerm" il est sur la branche "not running", mais affiche la notification "running", depuis la branche "is running"... La simple présence d'une "application tell" déclenchera l'ouverture de l'application puis l'exécution du service.

Y a-t-il un moyen de contourner ce problème ?

Merci et salutations.

0 votes

J'ai également rencontré ce problème et je l'ai trouvé très ennuyeux. Avez-vous trouvé des solutions récemment ? Merci.

1voto

zonble Points 2925

Les restrictions de sécurité d'El-Capitans ne sont PAS responsables du comportement erroné ci-dessus. J'ai testé le script un peu plus et j'ai trouvé que :

  • Toute phrase "est en cours d'exécution" doit être précédée d'un court "délai" pour donner une réponse vraie de manière fiable ... mais toujours ne le fera pas si elle est appelée en tant que service d'une application.

  • En outre, je suppose que les scripts d'Automator sont en quelque sorte "prétraités" avant d'être exécutés en tant que services.
    Toutes les branches if sont évaluées (jouées) et donc activées "au cas où".

Sur code jweaks à pile débordement iTerm n'est affecté directement que dans la deuxième clause ("tell ...").

tell application "System Events" to set theProcesses to name of every ¬
    every process whose visible is true

if theProcesses contains "iTerm" then display notification "running"
else [...]

Essayez ce code dans ScriptEditor, Automator et comme Service dans Safari :

display notification "" & running of application "TextEdit"
tell application "TextEdit" to activate
quit application "TextEdit"
display notification "" & running of application "TextEdit"

Vous obtiendrez des résultats différents avec AppleScript/Automator (=> false + vrai ) et Safari ( vrai + vrai ).
En particulier l'AppleScript/Automator vrai de la 2ème notification est assez révélateur.

... cependant, si vous insérez juste une minute de retard, disons 0,01, après la ligne "quit", l'exécution sera testée comme "fausse" - si le script est exécuté à partir d'AppleScript/Automator.

0voto

Pejvan Points 376

Parfois, j'ai aussi remarqué ce comportement en exécutant script, c'est étrange. Bien que la plupart du temps, cela ne se produit pas lorsqu'on n'exécute pas script par le biais de script Editor. Cependant, voici une meilleure alternative :

tell application "System Events"
    # Adding tell application block has no effect on the if condition
    # Try it with TextEdit, that's what I using to try this code, and works fine.
    if (the name of application processes as text) contains "iTerm" then
        # Will quit the application if running
        log "Running"
        tell application "iTerm" to quit
    else
        # Will launch the application otherwise.
        log "Not Running"
        tell application "iTerm" to activate
    end if
end tell

0 votes

Cela résoudrait-il mon problème ? Je suis capable de "loguer" l'application telle qu'elle fonctionne. Mais j'ai besoin d'interagir avec l'application (comme ouvrir un nouvel onglet ou non). En tant que tel, j'aurais besoin d'un bloc "tell application iTerm", n'est-ce pas ? Comment pourrais-je résoudre mon problème avec votre alternative ?

0 votes

Le journal est juste pour la démo, utilisez votre code comme vous le souhaitez.

0 votes

Je comprends cela. D'où mon bloc où j'utilise "display notification". Et comme je l'ai dit, tant que je n'utilise pas "tell application", le code fonctionne comme prévu, mais lorsque j'utilise un bloc tell application sur l'une ou l'autre branche, il affiche toujours "running". Dans votre exemple, essayez de remplacer "log "not running"" par un bloc tell application "iTerm", et vous verrez que vous enregistrerez toujours "running" et jamais "not running" (encore une fois, en exécutant le bloc comme un service). Je pense que vous n'avez peut-être pas lu complètement ma question. Merci quand même.

0voto

astroboylrx Points 101

Je viens de trouver un moyen de le faire. Bien que je crée une application au lieu d'un service, ils sont presque identiques. L'idée de base est de mettre tell application iTerm dans un autre script ou entre guillemets, de telle sorte que le processus d'optimisation ne lui fasse pas ouvrir iTerm avant d'exécuter ce script. Ainsi, vous obtiendrez le résultat réel de if application "iTerm" is running .

Mais dans le script cité, étant donné qu'il y a tell application partie, nous savons déjà qu'iTerm sera ouvert avant tout, nous pouvons directement activate iTerm et utiliser le current session of current terminal (en fait, même dans Automator, cela fonctionne même si iTerm n'est pas ouvert en premier). Je ne suis pas sûr que delay 0.01 est nécessaire ici (vous pouvez tester sur votre ordinateur). Mais celle-ci fonctionne pour mon objectif, qui est d'ouvrir le chemin actuel du Finder dans une nouvelle fenêtre iTerm sur le bureau actuel. Et si iTerm n'est pas lancé, il n'ouvrira pas deux fenêtres iTerm.

Faites-moi savoir ce que vous en pensez. :-)

on run {input, parameters}
    tell application "Finder"
        set dir_path to quoted form of (POSIX path of (folder of the front window as alias))
    end tell
    CD_to(dir_path)
end run

on CD_to(theDir)
    if application "iTerm" is running then
        #display dialog "Running" # for debug
        run script "
            on run {q}
                tell application \":Applications:iTerm.app\"
                    set term to (make new terminal) # make a new window in current desktop since I don't want to mess with current ones
                    tell term
                        launch session \"Default\"
                        set sesh to current session
                    end tell
                    tell sesh
                        write text \"cd \" & q & \";clear;\"
                    end tell
                    activate
                end tell
            end run
        " with parameters {theDir}
    else
        #display dialog "Not Running" # for debug
        run script "
            on run {q}
                tell application \":Applications:iTerm.app\"
                    delay 0.01
                    activate
                    set sesh to current session of current terminal
                    tell sesh
                        write text \"cd \" & q & \";clear;\"
                    end tell
                end tell
            end run
        " with parameters {theDir}
    end if
end CD_to
# part of code comes from http://peterdowns.com/posts/open-iterm-finder-service.html

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X