I've made a script which have a block of code launching Terminal to retrieve picture from a server, using FTP.
When I run the script under the script editor, everything is OK: the script launch the Terminal, open the FTP session, set the destination path, get the files, delete them from the server, close connexion, wait the end of Terminal activty and then quit.
But when I run my Script as application, in about 90% of cases, the app launch Terminal and then Terminal quit immediatly. When the Terminal seems to "get" correctly the FTP commands, connexion is done, getting file and so on. Perfectly. But this happens only in a few cases.
Here the last code I have for this part:
tell application "Terminal"
activate
-- Wait for "no more activity"
set frontWindow to window 1
repeat until busy of frontWindow is false
delay 1
end repeat
-- Perform FTP actins
set shell to do script "ftp -i ftp://user_ftp:pass_ftp#host_ftp/" in window 1
do script "lcd ~/Desktop/tmp_instagram/" in shell
do script "mget *.jpg" in shell
do script "mdel *.jpg" in shell
do script "bye" in shell
-- Wait for no more activity
set frontWindow to window 1
repeat until busy of frontWindow is false
delay 1
end repeat
end tell
tell application "Terminal" to quit saving no -- Saving no to avoid conf alert
For avoiding you to loose your time, here are some of the tests I've made, without any success:
Setting the whole FTP command in one line so.
Put a delay 5 after the ativate, rather than the repeat on busy
Put a delay after the ftp command
In fact, the Terminal seems to close before receiving the FTP command (opened and closed immediatly).
Thanks to Mark Setchell comment I tried without using the "shell" command and in fact it seems to be the key. Here is a piece of code which run correctly:
tell application "Terminal"
activate
set w to window frontmost
do script "ftp -i ftp://xxxxx:yy#dddddd/" in w
do script "lcd ~/Desktop/tmp_aarecno_instagram/" in w
do script "mget *.jpg" in w
do script "mdel *.jpg" in w
do script "bye" in w
set frontWindow to window 1
repeat until busy of frontWindow is false
delay 1
end repeat
end tell
This apple script is saved as application Mac_restart.app
After running Mac_restart.app mac restart and after restart this app is still on Dock as running app and i can click on restart it again, I have added the application quit but it didn't work.
i want to quite this app after restart and dont want on Dock as open application.
what i missing? kindly help.
if i don't put try in entire script app will throw error after some time AppleEvent time out (-1712) and i can see Edit option which i don't want that's why it put whole on try and if i put try on above handlers it will still continue to reboot i want until i press restart it shroud not restart.
Below is the final app which is not quit the app after restart. rest working fine.
try
with timeout of 400 seconds
tell application "Finder"
display dialog "Create Folder & Restart." buttons {"Cancel", "Ok"} default button 1 with icon 0 with title "Create Folder & Restart" giving up after 400
if the button returned of the result is "Cancel" then
return
end if
end tell
end timeout
try
do shell script "mkdir -p /Volumes/MAC/Users/jack/Desktop/2014"
do shell script "mkdir -p /Volumes/MAC/Users/jack/Desktop/2015"
do shell script "mkdir -p /Volumes/MAC/Users/jack/Desktop/2016"
do shell script "mkdir -p /Volumes/MAC/Users/jack/Desktop/2017"
end try
tell application "Finder"
activate
display dialog "Click on Restart." with icon 0 buttons ("Restart") giving up after 60
end tell
tell application "Finder"
restart
end tell
end try
If the script is saved as application use the on quit handler
on run
tell application "Finder"
activate
display dialog "Computer restart " with title "Restart Mac" with icon 0 buttons ("Restart Now")
end tell
quit
end run
on quit
tell application "Finder" to restart
continue quit
end quit
I'm trying to open terminal using apple script with a ready command but without executing it and allowing user to do this just by clicking enter (so I don't want to use tell Terminal to do script)
One of the approaches I used is using keystrokes:
tell application "Terminal" do script "echo Hi!"
keystroke "abc"
end tell
but it doesn't work for me. Any ideas?
I think you want to start Terminal and have a command all lined up ready in the Terminal ready for the user so he/she only has to press "Enter". If so, you can do this:
tell application "Terminal"
activate
delay 1
tell application "System Events"
keystroke "echo hi"
end tell
end tell
Then the user just has to press Enter and the command echo hi will execute.
it is hard to understand what you mean.
You can't for instance have the terminal wait for a user to click its window.
(But you can poll for a keystroke after the terminal window is opened.)
You'd have to use a dialog before your code, in order to make the user enter the terminal consciously.
display dialog "Press ok to enter the terminal" buttons {"Cancel","Enter"} cancel button 1 default button 2
Other than that, the way you'd need to use system events to send keystroke to the Terminal
tell application "System Events"
tell application process "Terminal"
keystroke "abcd"
end tell
end tell
You can poll for a keypress in the do script command to your terminal with this:
read -n 1 -s MYCHAR </dev/tty
This will force the user to press enter from a do script
a=`read`
I'm using AppleScript to open PostgreSQL in a Terminal tab like this:
#!/bin/bash
function new_tab() {
TAB_NAME=$1
COMMAND=$2
osascript \
-e "tell application \"Terminal\"" \
-e "tell application \"System Events\" to keystroke \"t\" using {command down}" \
-e "do script \"printf '\\\e]1;$TAB_NAME\\\a'; $COMMAND\" in front window" \
-e "end tell" > /dev/null
}
new_tab "PostgreSQL" "postgres -D /usr/local/var/postgres"
Running this script from the Terminal will open a new tab with PostgreSQL server inside. So at the end of the execution I'll have 2 tabs: the first one which was used to run the script, and the second one containing the server.
How can I close the first one?
This is my try:
osascript -e "tell application \"Terminal\" to close tab 1 of window 1"
But I get this error message:
execution error: Terminal got an error: tab 1 of window 1 doesn’t
understand the “close” message. (-1708)
You can try something like this:
tell application "Terminal"
activate
tell window 1
set selected tab to tab 1
my closeTabOne()
end tell
end tell
on closeTabOne()
activate application "Terminal"
delay 0.5
tell application "System Events"
tell process "Terminal"
keystroke "w" using {command down}
end tell
end tell
end closeTabOne
One way to do it is like this:
osascript \
-e "tell application \"Terminal\"" \
-e "do script \"exit\" in tab 1 of front window" \
-e "end tell" > /dev/null
But Terminal must be configured to close the window when the shell exits.
Anyone has a solution which does not need to do this?
This will close the active tab only:
tell application "Terminal" to close (get window 1)
To determine the tab’s window, you can parse the error message you get when trying to access the still non-existing window property of the tab. The error message usually contains the window's id with which you can reference the window.
As your question is 5 years old, I’ll finish my answer with example code that can be run in the Script Editor instead of a bash script which makes it hard to read.
tell application "Terminal"
-- Perform command
set theTab to do script "echo 'Hello World'"
try
-- Try to get the tab's window (this should fail)
set theWindow to window of theTab
on error eMsg number eNum
if eNum = -1728 then
(*
The error message should look like this:
Terminal got an error: Can’t get window of tab 1 of window id 6270.
*)
-- Specify the expected text that comes before the window id
set windowIdPrefix to "window id "
-- Find the position of the window id
set windowIdPosition to (offset of windowIdPrefix in eMsg) + (length of windowIdPrefix)
-- Get the window id (omitting the period and everything else after)
set windowId to (first word of (text windowIdPosition thru -1 of eMsg)) as integer
-- Store the window object in a variable
set theWindow to window id windowId
else
-- Some other error occurred; raise it
error eMsg number eNum
end if
end try
close theWindow
end tell
I think the key is to get the id of front window.
tell application "Terminal"
do script "pwd"
set myID to id of front window
close window id myID
end tell
I want to do something like this:
tell application "Terminal"
activate
do script "ssh user#server.com"
-- // write user's password
-- // write some linux commands to remote server
end tell
For example to log in to the server, enter the password, and then login to mysql and select a DB.
I type that every day and it would be really helpful to bundle it into a script.
Also, is there a reference of what commands, properties, functions, etc. do applications (Terminal, Finder, etc) have available to use within Applescript? thanks!
EDIT: Let me clear this up:
I don't want to do several 'do script' as I tried and doesn't work.
I want to open a Terminal window, and then emulate a human typing in some characters and hitting enter. Could be passwords, could be commands, whatever, just sending chars to the Terminal which happens to be running ssh. I tried keystroke and doesn't seem to work.
First connect to the server and wait for 6 seconds (you can change that) and then execute whatever you need on the remote server using the same tab
tell application "Terminal"
set currentTab to do script ("ssh user#server;")
delay 6
do script ("do something remote") in currentTab
end tell
As EvanK stated each do script line will open a new window however you can run two commands with the same do script by separating them with a semicolon. For example:
tell application "Terminal"
do script "date;time"
end tell
But the limit appears to be two commands.
However, you can append "in window 1" to the do script command (for every do script after the first one) to get the same effect and continue to run as many commands as you need to in the same window:
tell application "Terminal"
do script "date"
do script "time" in window 1
do script "who" in window 1
end tell
Note that I just used the who, date, and time command as an example...replace
with whatever commands you need.
Here's another way, but with the advantage that it launches Terminal, brings it to the front, and creates only one window.
I like this when I want to be neatly presented with the results of my script.
tell application "Terminal"
activate
set shell to do script "echo 1" in window 1
do script "echo 2" in shell
do script "echo 3" in shell
end tell
How about this? There's no need for key codes (at least in Lion, not sure about earlier), and a subroutine simplifies the main script.
The below script will ssh to localhost as user "me", enter password "myPassw0rd" after a 1 second delay, issue ls, delay 2 seconds, and then exit.
tell application "Terminal"
activate
my execCmd("ssh me#localhost", 1)
my execCmd("myPassw0rd", 0)
my execCmd("ls", 2)
my execCmd("exit", 0)
end tell
on execCmd(cmd, pause)
tell application "System Events"
tell application process "Terminal"
set frontmost to true
keystroke cmd
keystroke return
end tell
end tell
delay pause
end execCmd
You don't need to "tell" Terminal to do anything. AppleScript can do shell scripts directly.
set theDir to "~/Desktop/"
do shell script "touch " & theDir &"SomeFile.txt"
or whatever ...
Why don't use expect:
tell application "Terminal"
activate
set currentTab to do script ("expect -c 'spawn ssh user#IP; expect \"*?assword:*\"; send \"MySecretPass
\"; interact'")
end tell
Your question is specifically about how to get Applescript to do what
you want. But, for the particular example described, you might want
to look into 'expect' as a solution.
Kinda related, you might want to look at Shuttle (http://fitztrev.github.io/shuttle/), it's a SSH shortcut menu for OSX.
The last example get errors under 10.6.8 (Build 10K549) caused by the keyword "pause".
Replacing it by the word "wait" makes it work:
tell application "Terminal"
activate
my execCmd("ssh me#localhost", 1)
my execCmd("myPassw0rd", 0)
my execCmd("ls", 2)
my execCmd("exit", 0)
end tell
on execCmd(cmd, wait)
tell application "System Events"
tell application process "Terminal"
set frontmost to true
keystroke cmd
keystroke return
end tell
end tell
delay wait
end execCmd
I could be mistaken, but I think Applescript Terminal integration is a one-shot deal...That is, each do script call is like opening a different terminal window, so I don't think you can interact with it at all.
You could copy over the SSH public keys to prevent the password prompt, then execute all the commands joined together (warning: the following is totally untested):
tell application "Terminal"
activate
do script "ssh jdoe#example.com '/home/jdoe/dosomestuff.sh && /home/jdoe/dosomemorestuff.sh'"
end tell
Alternatively, you could wrap the ssh and subsequent commands in a shell script using Expect, and then call said shell script from your Applescript.
set up passwordless ssh (ssh-keygen, then add the key to ~/.ssh/authorized_keys on the server). Make an entry in ~/.ssh/config (on your desktop), so that when you run ssh mysqlserver, it goes to user#hostname... Or make a shell alias, like gotosql, that expands to ssh user#host -t 'mysql_client ...' to start the mysql client interactively on the server.
Then you probably do need someone else's answer to script the process after that, since I don't know how to set startup commands for mysql.
At least that keeps your ssh password out of the script!
Petruza,
Instead of using keystroke use key code.
The following example should work for you.
tell application "System Events"
tell application process "Terminal"
set frontmost to true
key code {2, 0, 17, 14}
keystroke return
end tell
end tell
The above example will send the characters {d a t e}
to Terminal and then keystroke return will enter and run
the command. Use the above example with whatever key codes you need
and you'll be able to do what you're trying to do.
what about something like this:
tell application "Terminal"
activate
do shell script "sudo dscl localhost -create /Local/Default/Hosts/cc.josmoe.com IPAddress 127.0.0.1"
do shell script "sudo dscl localhost -create /Local/Default/Hosts/cc.josmos2.com IPAddress 127.0.0.1"
end tell
As neat solution, try-
$ open -a /Applications/Utilities/Terminal.app *.py
or
$ open -b com.apple.terminal *.py
For the shell launched, you can go to Preferences > Shell > set it to exit if no error.
That's it.
I built this script. It is in Yosemite and it is bash script using AppleScript to choose a list of users for SSH servers. Basically you define an IP and then the user names.. when the application launches it asks who you want to login in as.. the SSH terminal is launched and logged in prompting a password...
(***
* --- --- --- --- ---
* JD Sports Fashion plc
* Apple Script
* Khaleel Mughal
* --- --- --- --- ---
* #SHELLSTAGINGSSHBASH
* --- --- --- --- ---
***)
set stagingIP to "192.162.999.999"
set faciaName to (choose from list {"admin", "marketing", "photography_cdn"})
if faciaName is false then
display dialog "No facia was selected." with icon stop buttons {"Exit"} default button {"Exit"}
else
set faciaName to (item 1 of faciaName)
tell application "Terminal"
activate
do script "ssh " & faciaName & "#" & stagingIP & ""
end tell
end if
I highly recommend though; Nathan Pickmans post above about Shuttle (http://fitztrev.github.io/shuttle/).. a very smart and simple application.