在新的 MacOSX 终端窗口中运行命令

我一直在试图弄明白如何在一个新的 Max OS X Terminal. app 窗口中运行 bash 命令。作为一个例子,下面是我如何在一个新的 bash 进程中运行我的命令:

bash -c "my command here"

但是,这将重用现有的终端窗口,而不是创建一个新的终端窗口:

Terminal.app -c "my command here"

但是这当然不管用。我知道“ open-a Terminal. app”命令,但是我不知道如何将参数转发到终端,甚至不知道使用什么参数。

147042 次浏览

one way I can think to do it off the top of my head is to create a .command file and run it like so:

echo echo hello > sayhi.command; chmod +x sayhi.command; open sayhi.command

or use applescript:

osascript -e 'tell application "Terminal" to do script "echo hello"'

although you'll either have to escape a lot of double quotes or not be able to use single quotes

Partial solution:

Put the things you want done in a shell-script, like so

#!/bin/bash
ls
echo "yey!"

And don't forget to 'chmod +x file' to make it executable. Then you can

open -a Terminal.app scriptfile

and it will run in a new window. Add 'bash' at the end of the script to keep the new session from exiting. (Although you might have to figure out how to load the users rc-files and stuff..)

Here's yet another take on it (also using AppleScript):

function newincmd() {
declare args
# escape single & double quotes
args="${@//\'/\'}"
args="${args//\"/\\\"}"
printf "%s" "${args}" | /usr/bin/pbcopy
#printf "%q" "${args}" | /usr/bin/pbcopy
/usr/bin/open -a Terminal
/usr/bin/osascript -e 'tell application "Terminal" to do script with command "/usr/bin/clear; eval \"$(/usr/bin/pbpaste)\""'
return 0
}


newincmd ls


newincmd echo "hello \" world"
newincmd echo $'hello \' world'

see: codesnippets.joyent.com/posts/show/1516

You could also invoke the new command feature of Terminal by pressing the Shift + ⌘ + N key combination. The command you put into the box will be run in a new Terminal window.

I've been trying to do this for a while. Here is a script that changes to the same working directory, runs the command, and closes the terminal window.

#!/bin/sh
osascript <<END
tell application "Terminal"
do script "cd \"`pwd`\";$1;exit"
end tell
END

In case anyone cares, here's an equivalent for iTerm:

#!/bin/sh
osascript <<END
tell application "iTerm"
tell the first terminal
launch session "Default Session"
tell the last session
write text "cd \"`pwd`\";$1;exit"
end tell
end tell
end tell
END

Here's my awesome script, it creates a new terminal window if needed and switches to the directory Finder is in if Finder is frontmost. It has all the machinery you need to run commands.

on run
-- Figure out if we want to do the cd (doIt)
-- Figure out what the path is and quote it (myPath)
try
tell application "Finder" to set doIt to frontmost
set myPath to finder_path()
if myPath is equal to "" then
set doIt to false
else
set myPath to quote_for_bash(myPath)
end if
on error
set doIt to false
end try


-- Figure out if we need to open a window
-- If Terminal was not running, one will be opened automatically
tell application "System Events" to set isRunning to (exists process "Terminal")


tell application "Terminal"
-- Open a new window
if isRunning then do script ""
activate
-- cd to the path
if doIt then
-- We need to delay, terminal ignores the second do script otherwise
delay 0.3
do script " cd " & myPath in front window
end if
end tell
end run


on finder_path()
try
tell application "Finder" to set the source_folder to (folder of the front window) as alias
set thePath to (POSIX path of the source_folder as string)
on error -- no open folder windows
set thePath to ""
end try


return thePath
end finder_path


-- This simply quotes all occurrences of ' and puts the whole thing between 's
on quote_for_bash(theString)
set oldDelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to "'"
set the parsedList to every text item of theString
set AppleScript's text item delimiters to "'\\''"
set theString to the parsedList as string
set AppleScript's text item delimiters to oldDelims
return "'" & theString & "'"
end quote_for_bash

I made a function version of Oscar's answer, this one also copies the environment and changes to the appropriate directory

function new_window {
TMP_FILE=$(mktemp "/tmp/command.XXXXXX")
echo "#!/usr/bin/env bash" > $TMP_FILE


# Copy over environment (including functions), but filter out readonly stuff
set | grep -v "\(BASH_VERSINFO\|EUID\|PPID\|SHELLOPTS\|UID\)" >> $TMP_FILE


# Copy over exported envrionment
export -p >> $TMP_FILE


# Change to directory
echo "cd $(pwd)" >> $TMP_FILE


# Copy over target command line
echo "$@" >> $TMP_FILE


chmod +x "$TMP_FILE"
open -b com.apple.terminal "$TMP_FILE"


sleep .1 # Wait for terminal to start
rm "$TMP_FILE"
}

You can use it like this:

new_window my command here

or

new_window ssh example.com

I call this script trun. I suggest putting it in a directory in your executable path. Make sure it is executable like this:

chmod +x ~/bin/trun

Then you can run commands in a new window by just adding trun before them, like this:

trun tail -f /var/log/system.log

Here's the script. It does some fancy things like pass your arguments, change the title bar, clear the screen to remove shell startup clutter, remove its file when its done. By using a unique file for each new window it can be used to create many windows at the same time.

#!/bin/bash
# make this file executable with chmod +x trun
# create a unique file in /tmp
trun_cmd=`mktemp`
# make it cd back to where we are now
echo "cd `pwd`" >$trun_cmd
# make the title bar contain the command being run
echo 'echo -n -e "\033]0;'$*'\007"' >>$trun_cmd
# clear window
echo clear >>$trun_cmd
# the shell command to execute
echo $* >>$trun_cmd
# make the command remove itself
echo rm $trun_cmd >>$trun_cmd
# make the file executable
chmod +x $trun_cmd


# open it in Terminal to run it in a new Terminal window
open -b com.apple.terminal $trun_cmd

A colleague asked me how to open A LOT of ssh sessions at once. I used cobbal's answer to write this script:

tmpdir=$( mktemp -d )
trap '$DEBUG rm -rf $tmpdir ' EXIT
index=1


{
cat <<COMMANDS
ssh user1@host1
ssh user2@host2
COMMANDS
} | while read command
do
COMMAND_FILE=$tmpdir/$index.command
index=$(( index + 1 ))
echo $command > $COMMAND_FILE
chmod +x  $COMMAND_FILE
open $COMMAND_FILE
done
sleep 60

By updating the list of commands ( they don't have to be ssh invocations ), you will get an additional open window for every command executed. The sleep 60 at the end is there to keep the .command files around while they are being executed. Otherwise, the shell completes too quickly, executing the trap to delete the temp directory ( created by mktemp ) before the launched sessions have an opportunity to read the files.

Another option that needs to be here is "ttab"

https://www.npmjs.com/package/ttab

Install
npm install ttab -g
Usage : Open another tab and run ls
ttab ls
Usage 2 : Open new tab, with Green BG, with title "hi", in directory ~/dev, and run code .
ttab -s Grass -t hi -d '~/dev' code .