Сервисный скрипт автоматизатора ВСЕГДА запускает приложение, не обращая внимания на условные

Я написал небольшой служебный скрипт, чтобы открыть окно терминала iTerm в произвольной папке в Finder.

Я хочу, чтобы он проверял, запущен ли iTerm, и должен ли он открывать сеанс терминала на новой вкладке, а не на существующей.

Сценарий выглядит следующим образом:

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

Проблема в том, что когда я запускаю скрипт как службу, он всегда будет вести себя так, как будто iTerm уже запущен (отображая «работающее» уведомление), даже если iTerm закрыт и явно НЕ работает.

Но если я вставлю тот же скрипт в редактор скриптов (установив для cdPath литерал, например set cdPath to "cd /etc") и выполню его напрямую, он будет работать правильно, либо открыв новый экземпляр iTerm, либо повторно используя существующий и создав новую вкладку, и отобразив соответствующий уведомления.

Что тут происходит? Почему запуск скрипта как службы будет определять приложение как работающее, несмотря ни на что?

Обновлять

Если я упрощу скрипт, чтобы просто отображать уведомления следующим образом:

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

Он будет вести себя так, как ожидалось (отображение «работает» или «не работает» соответственно).

Но если я добавлю часть «сказать приложение», она всегда будет проходить через «работающую» ветвь, несмотря ни на что.

Например:

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

Всегда будет открывать iTerm (даже если tell application "iTerm"он находится в «не работающей» ветке, но отображает «работающее» уведомление из ветки «работает»... Простое присутствие «сообщения о приложении» вызовет открытие приложения, а затем Служба запущена.

Есть ли способ обойти это?

Спасибо и привет.

Я также столкнулся с этой проблемой и нашел ее очень раздражающей. Были ли у вас какие-либо решения в последнее время? Спасибо.

Ответы (3)

Ограничения безопасности El-Capitans НЕ несут ответственности за ошибочное поведение, описанное выше. Я еще раз протестировал скрипт и обнаружил, что:

  • Любая фраза «выполняется» должна иметь короткую «задержку» перед ней, чтобы надежно вернуть истинный ответ ... но все же не будет этого делать, если она вызывается как служба приложения.
  • Кроме того, я предполагаю, что сценарии Automator каким-то образом «предварительно обрабатываются» перед запуском в качестве служб.
    Все if-ветви оцениваются (проигрываются) и тем самым активируются "на всякий случай".

В коде jweaks при переполнении стека iTerm затрагивается только непосредственно во втором предложении («рассказать...»).

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


Попробуйте этот код в ScriptEditor, Automator и как сервис в Safari:

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

Вы получите разные результаты от AppleScript/Automator (=> false + true ) и Safari ( true + true ). Особенно показательна правда
AppleScript/Automator из 2-го уведомления. ... однако, если вы вставите задержку всего в минуту, скажем, 0,01, после строки «выход», запуск будет проверен как «ложный» - если скрипт запускается из AppleScript/Automator.

Иногда я также замечал такое поведение при запуске скрипта, это странно. Хотя в большинстве случаев этого не происходит, если скрипт не запущен через редактор скриптов. Тем не менее, вот лучшая альтернатива:

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
Это решит мою проблему? Я могу «зарегистрировать» приложение, работающее как есть. Но мне нужно взаимодействовать с приложением (например, при открытии новой вкладки или нет). Таким образом, мне нужен блок «рассказать о приложении iTerm», верно? Как я могу решить свою проблему с помощью вашей альтернативы?
Журнал предназначен только для демонстрации, используйте свой код по своему усмотрению.
Я это понимаю. Отсюда мой блок, в котором я использую «отображать уведомление». И, как я уже сказал, пока я не использую код приложения «сообщение», он работает, как и ожидалось, но при использовании блока приложения сообщения в любой ветке он всегда будет показывать «работает». В вашем примере попробуйте заменить «журнал «не работает»» на блок сообщения приложения «iTerm», и вы увидите, что вы всегда будете регистрировать «работает» и никогда не «не работает» (опять же, выполнение блока как услуга). Я думаю, что вы, возможно, не прочитали мой вопрос полностью. Спасибо, в любом случае.
Ваш код функционально эквивалентен моему второму примеру кода, он не добавляет ничего нового, кроме другого способа выразить то же самое. Таким образом, это не ответ, а вы просто перефразируете мой вопрос ...: P В любом случае большое спасибо, но, пожалуйста, удалите этот ответ, если вам больше нечего добавить. С уважением.
Что еще добавить? Если нет, не могли бы вы удалить свой ответ? Это отвлекает внимание от вопросов, как будто на них уже есть ответы... Еще раз спасибо.
Эм... нет. Если приложение работает, оно зарегистрирует «Не работает» и запустит приложение, так как вы скажете ему активировать, если оно работает, ничего не произойдет, кроме как просто войти в журнал. Очевидно, что если вы запустите его несколько раз, то только в первый раз будет состояние «Не работает», а остальные будут «Выполняться», пока вы не выйдете из него. Вы можете сказать приложению выйти в рабочем блоке, и вы увидите, что условие выполняется, как и ожидалось.
Вы пробовали это как рабочий процесс службы? У меня есть, и он выдает "работает", открывает приложение, а потом закрывает его...
Посмотрите его здесь во всей его несостоятельной красе: vid.me/0fTZ :)
Само существование блока «сообщения» заставляет приложение открываться при выполнении службы...
Опять же, это не отвечает на мой вопрос. Пожалуйста, удалите этот ответ в его нынешнем виде. Спасибо и привет.

Я просто нашел способ сделать это. Хотя я создаю приложение вместо службы, они почти одинаковы. Основная идея состоит в том, чтобы поместить его tell application iTermв другой скрипт или в кавычки, чтобы процесс оптимизации не заставлял его открывать iTerm перед выполнением этого скрипта. Таким образом, вы получите реальный результат if application "iTerm" is running.

Но в процитированном скрипте, поскольку есть tell applicationчасть, мы уже знаем, что iTerm будет открыт раньше всего, мы можем напрямую использовать activateiTerm и использовать его current session of current terminal(на самом деле, даже в Automator это все еще работает, даже если iTerm не открывается сначала). Я не уверен, что delay 0.01здесь это необходимо (вы можете проверить на своем компьютере). Но это работает для моей цели, которая заключается в том, чтобы открыть текущий путь Finder в новом окне iTerm на текущем рабочем столе. И если iTerm не запущен, он не откроет два окна iTerm.

Дайте мне знать, что вы думаете. :-)

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