Escribí un pequeño script de servicio para abrir una ventana de terminal iTerm en una carpeta arbitraria en Finder.
Quiero que verifique si iTerm se está ejecutando y si es para abrir la sesión de terminal en una nueva pestaña en lugar de en una existente.
El guión es así:
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
El problema es que cuando ejecuto el script como un servicio, siempre se comportará como si iTerm ya se estuviera ejecutando (mostrando la notificación "en ejecución"), incluso si iTerm está cerrado y claramente NO se está ejecutando.
Pero si pego la misma secuencia de comandos en el Editor de secuencias de comandos (configurando cdPath en un literal, como set cdPath to "cd /etc"
) y la ejecuto directamente, funcionará correctamente, ya sea abriendo una nueva instancia de iTerm o reutilizando una existente y creando una nueva pestaña, y mostrar la correspondiente notificaciones
¿Que está pasando aqui? ¿Por qué ejecutar el script como un servicio detectaría que la aplicación se está ejecutando sin importar qué?
Actualizar
Si simplifico el script para que solo muestre las notificaciones de esta manera:
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
Se comportará como se espera (mostrando 'en ejecución' o 'no en ejecución' según corresponda).
Pero si agrego la parte "decir a la aplicación", siempre irá a través de la rama "en ejecución", pase lo que pase.
P.ej:
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
Siempre abrirá iTerm (incluso si tell application "iTerm"
está en la rama "no en ejecución", pero mostrará la notificación "en ejecución", desde la rama "en ejecución"... La mera presencia de una "aplicación de aviso" activará la apertura de la aplicación y luego se ejecuta el Servicio.
¿Hay alguna manera de eludir esto?
Gracias y saludos.
Las restricciones de seguridad de El-Capitans NO son responsables del comportamiento erróneo anterior. Probé el script un poco más y descubrí que:
En el código jweaks en el desbordamiento de la pila , iTerm solo se ve afectado directamente en la segunda cláusula ("decir...").
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 [...]
Pruebe este código en ScriptEditor, Automator y como servicio en Safari:
display notification "" & running of application "TextEdit"
tell application "TextEdit" to activate
quit application "TextEdit"
display notification "" & running of application "TextEdit"
Obtendrá diferentes resultados de AppleScript/Automator (=> false + true ) y Safari ( true + true ). Especialmente la verdad
de AppleScript/Automator desde la segunda notificación es bastante reveladora. ... sin embargo, si inserta solo un minuto de retraso, digamos 0.01, después de la línea "salir", la ejecución se probará como "falsa", si el script se ejecuta desde AppleScript/Automator.
A veces también he notado ese comportamiento al ejecutar el script, es extraño. Aunque la mayoría de las veces no sucede cuando no se ejecuta el script a través del Editor de scripts. Sin embargo, aquí hay una mejor alternativa:
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
Acabo de encontrar una manera de hacerlo. Aunque estoy creando una aplicación en lugar de un servicio, son casi lo mismo. La idea básica es poner tell application iTerm
en otro script o entre comillas, de modo que el proceso de optimización no haga que se abra iTerm antes de ejecutar este script. Así obtendrás el resultado real de if application "iTerm" is running
.
Pero en el script citado, dado que hay tell application
una parte, ya sabemos que iTerm se abrirá antes que nada, podemos activate
iTerm directamente y usar el current session of current terminal
(de hecho, incluso en Automator, esto todavía funciona incluso si iTerm no se abre primero). No estoy seguro si delay 0.01
es necesario aquí (puede probar en su computadora). Pero este funciona para mi propósito, que es abrir la ruta actual del Finder en una nueva ventana de iTerm en el escritorio actual. Y si iTerm no se está ejecutando, no abrirá dos ventanas de iTerm.
Déjame saber lo que piensas. :-)
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
astroboylrx