I can launch an xterm from the command line (or a program, via a system call) like so:
/usr/X11/bin/xterm -fg SkyBlue -bg black -e myscript
That will launch an xterm with blue text and a black background, and run an arbitrary script inside it.
My question: How do I do the equivalent with Terminal.app?
You can open an app by bundle id too, and give other parameters.
If there's an executable script test.sh in the current directory, the following command will open and run it in Terminal.app
open -b com.apple.terminal test.sh
The only down side that I can find is that Terminal doesn't appear to inherit your current environment, so you'll have to arrange another way to pass parameters through to the script that you want to run. I guess building the script on the fly to embed the parameters would be one approach (taking into account the security implications of course...)
Assuming you already have the colors you want in one of your Terminal profiles, here's what I came up with (with some help from Juha's answer and from this Serverfault answer).
Update:
On reflection, I think this echo business is too complicated. It turns out you can use osascript to make an executable AppleScript file with a shebang line:
#!/usr/bin/osascript
on run argv
if length of argv is equal to 0
set command to ""
else
set command to item 1 of argv
end if
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application "Terminal"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
Save that as term.scpt, make it executable with chmod +x, and use it the same way as below, e.g. term.scpt "emacs -nw" "Red Sands".
Original answer:
Assuming we save the script below as term.sh...
#!/bin/sh
echo '
on run argv
if length of argv is equal to 0
set command to ""
else
set command to item 1 of argv
end if
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application "Terminal"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application "Terminal" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
' | osascript - "$#" > /dev/null
...it can be invoked as follows:
term.sh
opens a new terminal window, nothing special
term.sh COMMAND
opens a new terminal window, executing the specified command. Commands with arguments can be enclosed in quotes, e.g. term.sh "emacs -nw" to open a new terminal and run (non-windowed) emacs
term.sh COMMAND PROFILE
opens a new terminal window, executing the specified command, and sets it to the specified profile. Profiles with spaces in their names can be enclosed in quotes, e.g. term.sh "emacs -nw" "Red Sands" to open a new terminal and run (non-windowed) emacs with the Red Sands profile.
If you invoke it with a bad command name, it'll still open the window and set the profile, but you'll get bash's error message in the new window.
If you invoke it with a bad profile name, the window will still open and the command will still execute but the window will stick with the default profile and you'll get an error message (to stderr wherever you launched it) along the lines of
525:601: execution error: Terminal got an error: Can’t get settings set 1 whose name = "elvis". Invalid index. (-1719)
The invocation is slightly hacky, and could probably be improved if I took the time to learn getopt (e.g., something like term.sh -p profile -e command would be better and would, for instance, allow you to easily open a new terminal in the specified profile without invoking a command). And I also wouldn't be surprised if there are ways to screw it up with complex quoting. But it works for most purposes.
Almost all (every?) osx program can be launched from command line using:
appName.app/Contents/MacOS/command
For terminal the command is:
/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal
You can use the autocomplete (tab) or ls to find the correct filenames. ".app" is basically a folder.
To change the colors and run a script... I think you cannot do it with shell scripts as Terminal does not accept arguments ("Terminal myScript.sh" does not launch myScript). With iTerm this works.
Workaround is to use applescript (wrapped in a shell script):
#!/bin/sh
osascript -e '
tell application "Terminal"
activate
tell window 1
do script "sleep 5; exit"
set background color to {0, 11111, 11111}
set win_id to id
end tell
set w_ids to (id of every window)
repeat while w_ids contains win_id
delay 1
set w_ids to (id of every window)
end repeat
end tell'
Ok, now it should behave exactly the same as the xterm example. The drawback is the constant polling of the window ids (which is bad programming).
edit: A bit more elegant applescript would use the 'busy' property of Terminal. I will leave the original code as is works for a general program (not just terminal).
tell application "Terminal"
tell window 1
do script "sleep 2"
set background color to {0, 11111, 11111}
repeat while busy
delay 1
end repeat
close
end tell
end tell
Also for perfectly correct program, one should check that whether the terminal is running or not. It affects the number of windows opened. So, this should be run first (again a nasty looking hack, that I will edit later as I find a working solution).
tell application "System Events"
if (count (processes whose name is "Terminal")) is 0 then
tell application "Terminal"
tell window 1
close
end tell
end tell
end if
end tell
br,
Juha
You can also go into terminal GUI, completely configure the options to your heart's content, and export them to a ".terminal" file, and/or group the configurations into a Window Group and export that to a terminal file "myGroup.terminal". Then
open myGroup.terminal
will open the terminal(s) at once, with all your settings and startup commands as configured.
you can launch terminal with the following command, not sure how to specify colors:
open /Applications/Utilities/Terminal.app/
The answer from #david-moles above works but run the terminal and command in ~ rather the current working directory where term was launched. This variation adds a cd command.
#!/usr/bin/env bash
# based on answer by #david-moles in
# https://stackoverflow.com/questions/4404242/programmatically-launch-terminal-app-with-a-specified-command-and-custom-colors
echo "
on run argv
if length of argv is equal to 0
set command to \"\"
else
set command to item 1 of argv
end if
set command to \"cd '"$PWD"' ;\" & command
if length of argv is greater than 1
set profile to item 2 of argv
runWithProfile(command, profile)
else
runSimple(command)
end if
end run
on runSimple(command)
tell application \"Terminal\"
activate
set newTab to do script(command)
end tell
return newTab
end runSimple
on runWithProfile(command, profile)
set newTab to runSimple(command)
tell application \"Terminal\" to set current settings of newTab to (first settings set whose name is profile)
end runWithProfile
" | osascript - "$#" > /dev/null
There may be a way to set PWD this with applescript.
Note: When I use this, I sometimes two Terminal windows, one a shell running in ~ and a second which runs the cd command and command from argv[1]. Seems to happen if Terminal is not already running; perhaps it is opening old state (even tho I had no open terminals when I closed it).
For several reasons I must test my program with multiple computer restart.
So I need at the computer startup, eclipse open and the tested program runs in eclipse (in debug mode if possible).
Can you give me a command line or another way to do that. I just need when I open eclipse or when I use the given command line, the program automatically start
Thank you
For Linux OS (not sure on Win, Mac), Eclipse (or other apps) can be automated with xdotool utility. Assuming your app has run at least once in debug mode within Eclipse so it exists an entry on Debug history, a Bash script could do the following actions
-Edit the script below to set the correct position value for the app.
-Launch Eclipse.
-Wait some time until is fully up.
-Execute the following command sequence:
#!/bin/bash
position=6
#find Eclipse app window IDs, keep the last one
e_wid=$(xdotool search --class Eclipse | gawk 'END{print $0}')
# Create basic command string
cmd="xdotool windowactivate --sync $e_wid"
# Send key strokes with some delay in between
# Open Run menu
$cmd key Alt+r
sleep 1
# select Debug option
$cmd key h
sleep 0.5
# pick the sixth option in that menu
$cmd key $position
It's recommended to mark the app as a favorite so it gets a constant order in the menu.
To see another example, check this mluis7 gist at Github.
I am having a strange issue. I have written a script which is basically running a perl script in remote server using ssh.
This script is working fine but after completion of the above operation it will ask user to choose the next operation.
it is showing the options in the command prompt but while I am giving any input it is not showing in the screen even after hitting enter also it remain same.
I am not getting what is the exact issue, but it seems there is some issue with the ssh command because if I am commenting out the ssh command it is working fine.
OPERATION:
print "1: run the script in remote server \n2: Exit\n\nEnter your choice:";
my $input=<STDIN>;
chomp($input);
..........
sub run_script()
{
my $com="sshg3.exe server -q --user=user --password=pass -exec script >/dev/null";
system("$com");
goto OPERATION;
}
after completing this ssh script it is showing in screen:
1: run remote script
2: exit
Enter your choice:
but while I am giving any input it is not displaying in the screen until and unless I am exiting it using crtl C.
Please can anyone help what might be the issue here ?
One of the classic gotchas with ssh is this - that it normally runs interactively, and as such will attach STDIN by default.
This can result in STDIN being consumed by ssh rather than your script.
Try it with ssh -n instead.
You can redirect the output in command prompt if -n option is not available for you.
try this one it might work for you.
system("$com />null");
As per https://support.ssh.com/manuals/client-user/62/sshg3.html there is an option for redirecting input use --dev-null (*nix) or --null (Windows).
-n, --dev-null (Unix), -n, --null (Windows)
Redirects input from /dev/null (Unix) and from NUL (Windows).
I'm trying to run a powershell script from within Cygwin (ultimately will be run over Cygwin SSH), and am finding that user input seems to be ignored. The script displays a menu and then uses Read-Host "Your selection:" to receive the input.
There is a blinking cursor, but the "Your selection" text doesn't appear, and anything I enter seems to just write to the console itself and is ignored by the script.
Does anyone know what could be wrong?
Thanks very much.
I'm guessing Cygwin console does not implement the APIs that the Powershell console's host (System.Management.Automation.Internal.Host.InternalHostUserInterface) depends on. Or doesn't implement them as expected. This will surely be the case if you attempt to run over SSH. MS has documentation on how to write a custom Host UI. So if you want to run PS over SSH seems like there are 4 possibilities:
Write your own PSHost implementation
Find someone else's PSHost implementation
Use your SSH's clients stdin and stdout as a two way pipe and write a REPL that takes input from the pipe (SSH stdin) and sends output to the pipe (SSH stdout). Unless you implement it yourself, this option means you lose line editing, history, tab completion, etc.
Not sure if this one will work, but it would might be the least amount of code to implement if it does. Create a child PS process. Redirect the child's stdout, stdin to the parent PS process. All input you get from SSH stdin you write to child PS's stdin and all output you read from child's stdout you write to SSH stdout. You'll probably want to use asynchronous I/O for the reads on SSH stdin and child's stdout, to prevent hangs (if script is waiting on a read from child's stdout, but the child PS has no more output, then the script is hung). In effect the SSH user is controlling the child PS process and the parent PS process is just the glue joining the two together.
I'm debugging a problem with a script not emailing out.
When i execute the following outside of the script:
mail -s "testing" myemail#gmail.com
It just hangs. The terminal doesn't give me any feedback what it's doing or if it has finished. I can only enter a another command by CTRL + Cing it. Any ideas why? Sometimes it does work if I let it hang long enough (I will get an email about 2 - 4 minutes later).
I'm running CENTOS 5 something. I've just uninstalled sendmail and installed postfix to see if this fixes it and the same thing appears to be happening.
If you enter the above and hit it should take you to a blank line and wait for you to type the actual text of the message. Once you've completed entering the message, you enter a .<enter> (dot or period followed by enter key) as the first character on a line and (depending on the version), it will usually ask you to enter any CC: addresses. Hit again to proceed past that and it should then send the mail.
The above command doesn't actually send anything, the -s sets the subject, but unless you include a file it will simply wait for you to type something. If, on the other hand, you want it to just send something quickly you can have it pull in a file as the content of the message, e.g. mail -s "testing" myemail#gmail.com < some_text_file. This will read some_text_file into the body of the email and send it immediately.