Das Automator-Dienstskript startet IMMER die Anwendung, ungeachtet der Bedingung

Ich habe ein kleines Dienstskript geschrieben, um ein iTerm-Terminalfenster in einem beliebigen Ordner im Finder zu öffnen.

Ich möchte, dass überprüft wird, ob iTerm ausgeführt wird und ob die Terminalsitzung in einem neuen Tab statt in einem vorhandenen geöffnet wird.

Das Skript geht so:

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

Das Problem ist, dass, wenn ich das Skript als Dienst ausführe, es sich immer so verhält, als ob iTerm bereits ausgeführt würde (es wird die Benachrichtigung "Ausgeführt" angezeigt), selbst wenn iTerm geschlossen ist und ganz klar NICHT ausgeführt wird.

Aber wenn ich dasselbe Skript in den Skripteditor einfüge (cdPath auf ein Literal, wie set cdPath to "cd /etc") und es direkt ausführe, funktioniert es korrekt, indem ich entweder eine neue iTerm-Instanz öffne oder eine vorhandene wiederverwende und eine neue Registerkarte erstelle und das entsprechende zeige Benachrichtigungen.

Was ist denn hier los? Warum würde das Ausführen des Skripts als Dienst erkennen, dass die Anwendung ausgeführt wird, egal was passiert?

Aktualisieren

Wenn ich das Skript vereinfache, um nur die Benachrichtigungen wie folgt anzuzeigen:

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

Es verhält sich wie erwartet (es wird entsprechend „running“ oder „not running“ angezeigt).

Aber wenn ich den Teil "Tell Application" hinzufüge, wird er immer den durchgehenden "Running"-Zweig durchlaufen, egal was passiert.

Z.B:

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

Öffnet immer iTerm (selbst wenn es tell application "iTerm"sich im Zweig "nicht läuft" befindet, aber die Benachrichtigung "wird ausgeführt" aus dem Zweig "wird ausgeführt" anzeigen ... Das bloße Vorhandensein einer "Tell-Anwendung" löst dann das Öffnen der App aus Der Dienst wird ausgeführt.

Gibt es eine Möglichkeit, dies zu umgehen?

Danke und Grüße.

Ich bin auch auf dieses Problem gestoßen und fand es sehr nervig. Haben Sie in letzter Zeit Lösungen gefunden? Danke schön.

Antworten (3)

Die Sicherheitsbeschränkungen von El-Capitans sind NICHT für das oben genannte fehlerhafte Verhalten verantwortlich. Ich habe das Skript noch etwas getestet und folgendes festgestellt:

  • Jeder "läuft"-Satz muss eine kurze "Verzögerung" davor haben, um zuverlässig eine wahre Antwort zurückzugeben ... wird dies aber immer noch nicht tun, wenn er als Dienst einer App aufgerufen wird.
  • Außerdem vermute ich, dass Automator-Skripte irgendwie "vorverarbeitet" werden, bevor sie als Dienste ausgeführt werden.
    Alle if-Verzweigungen werden ausgewertet (durchgespielt) und dadurch "für alle Fälle" aktiviert.

In jweaks-Code bei Stapelüberlauf ist iTerm nur direkt in der 2. Klausel ("tell ...") betroffen .

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 [...]


Probieren Sie diesen Code im ScriptEditor, Automator und als Dienst in Safari aus:

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

Sie erhalten unterschiedliche Ergebnisse von AppleScript/Automator (=> false + true ) und Safari ( true + true ). Besonders das True
von AppleScript/Automator aus der 2. Benachrichtigung ist ziemlich aufschlussreich. ... wenn Sie jedoch nur eine Minute Verzögerung einfügen, z. B. 0,01, nach der Zeile "quit", wird die Ausführung als "false" getestet - wenn das Skript von AppleScript/Automator aus ausgeführt wird.

Manchmal habe ich dieses Verhalten auch beim Ausführen von Skripten bemerkt, es ist seltsam. Obwohl es meistens nicht passiert, wenn das Skript nicht über den Skripteditor ausgeführt wird. Hier ist jedoch eine bessere 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
Würde das mein Problem lösen? Ich bin in der Lage, die laufende Anwendung so zu "protokollieren", wie sie ist. Aber ich muss mit der App interagieren (wie beim Öffnen eines neuen Tabs oder nicht). Als solches bräuchte ich einen "Tell Application iTerm" -Block, oder? Wie könnte ich mein Problem mit Ihrer Alternative lösen?
Log dient nur zu Demozwecken, verwenden Sie Ihren Code nach Belieben.
Ich verstehe das. Daher mein Block, in dem ich "Benachrichtigung anzeigen" verwende. Und wie gesagt, solange ich keinen "Tell Application"-Code verwende, funktioniert er wie erwartet, aber wenn ich einen Tell-Application-Block in einem der Zweige verwende, wird immer "running" angezeigt. Versuchen Sie in Ihrem Beispiel, "log "not running"" durch einen Tell-Application-"iTerm"-Block zu ersetzen, und Sie werden sehen, dass Sie immer "running" und niemals "not running" protokollieren (erneut wird der Block als Service). Ich glaube, Sie haben meine Frage vielleicht nicht ganz gelesen. Trotzdem danke.
Ihr Code ist funktional äquivalent zu meinem zweiten Codebeispiel, er fügt nichts Neues hinzu, sondern eine andere Möglichkeit, dasselbe auszudrücken. Daher ist dies keine Antwort, sondern Sie formulieren nur meine Frage um ... : P Trotzdem vielen Dank, aber bitte entfernen Sie diese Antwort, wenn Sie nichts hinzuzufügen haben. Grüße.
Gibt es noch etwas hinzuzufügen? Wenn nicht, könnten Sie bitte Ihre Antwort entfernen? Es lenkt die Aufmerksamkeit von den Fragen ab, da es so aussieht, als wären sie bereits beantwortet ... Nochmals vielen Dank.
Ähm nein. Wenn die Anwendung ausgeführt wird, protokolliert sie "Nicht ausgeführt" und startet die Anwendung, da Sie ihr sagen, dass sie aktiviert werden soll. Wenn sie ausgeführt wird, passiert nichts anderes als nur eine Protokollierung. Wenn Sie es mehrmals ausführen, ist natürlich nur das erste Mal der Zustand "Nicht ausgeführt" und der Rest ist "Ausgeführt", bis Sie es beenden. Sie können der Anwendung sagen, dass sie im laufenden Block beendet werden soll, und Sie sehen, dass die Bedingung wie erwartet gehalten wird.
Haben Sie es als Service-Workflow versucht? Ich habe, und es erzeugt "running", öffnet die Anwendung und schließt sie dann ...
Seht es euch hier in all seiner gescheiterten Pracht an: vid.me/0fTZ :)
Die bloße Existenz des "Tell"-Blocks öffnet die App, wenn der Dienst ausgeführt wird ...
Das beantwortet wiederum nicht meine Frage. Bitte entfernen Sie diese Antwort unverändert. Danke und Grüße.

Ich habe gerade einen Weg gefunden, es zu tun. Obwohl ich eine Anwendung anstelle eines Dienstes erstelle, sind sie fast gleich. Die Grundidee besteht darin, es tell application iTermin ein anderes Skript oder in Anführungszeichen zu setzen, sodass der Optimierungsprozess es nicht dazu bringt, iTerm zu öffnen, bevor dieses Skript ausgeführt wird. So erhalten Sie das tatsächliche Ergebnis von if application "iTerm" is running.

Aber in dem zitierten Skript, da es einen tell applicationTeil gibt, wissen wir bereits, dass iTerm vor allem geöffnet wird, wir können direkt activateiTerm und verwenden current session of current terminal(tatsächlich funktioniert dies sogar in Automator, auch wenn iTerm nicht zuerst geöffnet wird). Ich bin mir nicht sicher, ob delay 0.01dies hier erforderlich ist (Sie können es auf Ihrem Computer testen). Aber dieser funktioniert für meinen Zweck, nämlich den aktuellen Finder-Pfad in einem neuen iTerm-Fenster auf dem aktuellen Desktop zu öffnen. Und wenn iTerm nicht läuft, werden keine zwei iTerm-Fenster geöffnet.

Lass mich wissen was du denkst. :-)

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