3

I wrote a little service script to open an iTerm terminal window on an arbitrary folder on Finder.

I want it to check if iTerm is running, and if it is to open the terminal session in a new tab instead of on an existing one.

The script goes like this:

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

Problem is that when I run the script as a service, it will always behave as if iTerm was already running (displaying the "running" notification), even if iTerm is closed and very clearly NOT running.

But if I paste the same script to the Script Editor (setting cdPath to a literal, like set cdPath to "cd /etc") and execute it directly it will work correctly, either opening a new iTerm instance or reusing an existing one and creating a new tab, and display the corresponding notifications.

What's going on here? Why running the script as a service would detect the application as running no matter what?

Update

If I simplify the script to just displaying the notifications like this:

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

It'll behave as expected (displaying 'running' or 'not running' accordingly).

But if I add the "tell application" part, it will always go the through "running" branch, no matter what.

E.g.:

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

Will always open iTerm (even if the tell application "iTerm" it's on the "not running" branch, but display the "running" notification, from the "is running" branch... The mere presence of a "tell application" will trigger opening the app then the Service is run.

Is there a way to circumvent this?

Thanks and regards.

  • I also encountered this problem and found it very annoying. Have you got any solutions recently? Thank you. – astroboylrx May 26 '16 at 3:03
1

El-Capitans security restrictions are NOT responsible for erroneous behaviour above. I tested the script some more and found that:

  • Any "is running"-phrase needs to have a short "delay" in front of it to reliably return a true answer ... but still won't do so if called as an app's service.
  • Furthermore I guess that Automator scripts are somehow "pre-processed" before being run as Services.
    All if-branches are evaluated (played through) and thereby activated "just in case".

In jweaks code at stackoverflow, iTerm is only affected directly in the 2nd 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 [...]


Try this code in ScriptEditor, Automator and as Service in Safari:

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

You will get different results from AppleScript/Automator (=> false + true) and Safari (true + true).
Especially AppleScript/Automator's true from the 2nd notification is quite telling.

... however, if you insert just a minute delay, say 0.01, after the "quit" line, running will be tested as "false" - if the script is run from within AppleScript/Automator.

0

Sometimes I've also noticed that behaviour when running script, it's odd. Although most times it doesn't happen when not running script through Script Editor. However, here is a better 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
  • Would that solve my problem? I'm able to "log" the application running as it is. But I need to interact with the app (as in opening a new tab or not). As such I'd need a "tell application iTerm" block, right? How could I address my problem with your alternative? – yivi Nov 15 '15 at 16:56
  • Log is just for demo, use your code as you desire. – user14492 Nov 15 '15 at 17:00
  • I understand that. Hence my block where I use 'display notification'. And as I said, as long as I don't use "tell application" code works as expected, but when using a tell application block on either branch, it'll always show "running". In your example, try replacing 'log "not running"' with a tell application "iTerm" block, and you'll see that you'll always log "running" and never "not running" (again, executing the block as a service). I think you may have not read my question completely. Thanks anyway. – yivi Nov 15 '15 at 17:04
  • Your code is functionally equivalent to my second code example, it doesn't add anything new but another way to express the same. As such, this is not an answer but you are just rephrasing my question... :P Many thanks anyway, but please remove this answer if you don't have anything else to add. Regards. – yivi Nov 15 '15 at 17:07
  • Anything else to add? If not, please could you remove your answer? It detracts attention from the questions, as it appears as if it were already answered... Thanks again. – yivi Nov 15 '15 at 17:40
0

I just found a way to do it. Although I'm creating an application instead of a service, they are almost the same. The basic idea is to put tell application iTerm into another script or into quotes, such that the optimization process won't make it open iTerm before executing this script. Thus you'll get the real result of if application "iTerm" is running.

But in the quoted script, since there is tell application part, we already know iTerm will be open before anything, we can directly activateiTerm and use the current session of current terminal (in fact, even in Automator, this still works even if iTerm is not opened firstly). I'm not sure if delay 0.01 is necessary here (you can test in your computer). But this one works for my purpose, which is to open current Finder path in a new iTerm window in current desktop. And if iTerm is not running, it won't open two iTerm windows.

Let me know what you think. :-)

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .