Запуск команди у новому вікні терміналу Mac OS X.


92

Я намагався зрозуміти, як запустити команду bash у новому вікні Max OS X Terminal.app. Як приклад, ось як я б запустив свою команду в новому процесі bash:

bash -c "my command here"

Але це використовує існуюче вікно терміналу замість того, щоб створювати нове. Я хочу щось на зразок:

Terminal.app -c "my command here"

Але, звичайно, це не працює. Мені відомо про команду "open -a Terminal.app", але я не бачу, як пересилати аргументи в термінал, і навіть якщо я робив, які аргументи використовувати.


Ви завжди можете відкрити налаштування, перейти на вкладку "Профілі", зайти на сторінку "Оболонка" і встановити там команду запуску. Він працює лише тоді, коли додаток відкрито, але працює краще, ніж хакі!
Зейн Хелтон,

Також див. Те саме питання на superuser superuser.com/q/174576/122841
Жук

Відповіді:


96

один із способів, як я можу подумати, як це зробити, - створити файл .command і запустити його так:

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

або використовуйте applecript:

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

хоча вам або доведеться уникати багатьох подвійних лапок, або не мати змоги використовувати одинарні лапки


Я визначився з першим методом. Це досить хак, але це працює, і мені не доведеться турбуватися про те, щоб уникнути лапок у моїй команді чи щось інше. Дякую.
Walt D

3
Якщо команду потрібно запустити параметризованою, можливо, вам захочеться поміняти місцями одинарні та подвійні лапки; хоча вам потрібно зрозуміти різницю, щоб мати змогу це зробити правильно. osascript -e "tell application \"Terminal\" to do script \"echo '$variable'\"'
триплі

хтось знає, як закрити дурне ліве вікно терміналу?
Nicholas DiPiazza

Додайте ; exitв кінці команди сценарію оболонки, наприклад do script "echo hello; exit". Вам все одно потрібно закрити вікно окремо.
триплі

65

Часткове рішення:

Помістіть те, що ви хочете зробити, у сценарій оболонки, приблизно так

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

І не забудьте ' chmod +x file', щоб зробити його виконуваним. Тоді можна

open -a Terminal.app scriptfile

і він запуститься в новому вікні. Додайте ' bash' в кінці сценарію, щоб новий сеанс не закривався. (Хоча, можливо, вам доведеться зрозуміти, як завантажити користувачам rc-файли та інше ..)


7
Здається, контекстом нещодавно відкритого вікна є коренева папка користувача /Users/{username}. Чи є спосіб зберегти теку контексту такою ж, як вікно батьківського терміналу, яке її відкрило?
Johnny Oshika,

> Хоча вам, можливо, доведеться розібратися, як завантажити користувачам rc-файли та інше .. використовуйте для цього bash -l
Айвар,

35

Я намагався це зробити вже деякий час. Ось сценарій, який змінюється в тому ж робочому каталозі, запускає команду і закриває вікно терміналу.

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

Не подобається прийнятий сценарій, ваш вирішує поточну проблему каталогу. Дякую!
Марбоні,

Відмінне рішення; він виводить щось на зразок tab 1 of window id 7433stdout в запусковій оболонці. Щоб придушити це, розмістіть >/dev/null перед цим <<END .
mklement0

1
Це по суті не закриває вікно терміналу. Він просто виходить з інтерпретатора команд. Terminal.app повинен бути налаштований на автоматичне закриття вікна або на чистий вихід інтерпретатора команд.
user66001

8

Якщо хтось піклується, ось 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

3

Ось ще одне рішення (також за допомогою 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' 

див .: codenippets.joyent.com/posts/show/1516


3

Я зробив функціональну версію відповіді Оскара, вона також копіює середовище та зміни у відповідний каталог

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"
}

Ви можете використовувати його так:

new_window my command here

або

new_window ssh example.com

1
Лінія TMP_FILE="tmp.command"може бути проблемою, якщо одночасно запускати більше одного процесу. Я б запропонував замінити його наTMP_FILE=$(mktemp "/tmp/command.XXXXXX")
квітня

2

Ось мій чудовий скрипт, він створює нове вікно терміналу, якщо це потрібно, і перемикається в каталог, у якому знаходиться Finder, якщо Finder передовий. У ньому є все обладнання, необхідне для запуску команд.

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

1

Колега запитав мене, як одразу відкрити БАГАТО сеансів ssh. Я використав відповідь cobbal, щоб написати цей сценарій:

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

Оновивши список команд (вони не повинні бути викликами ssh), ви отримаєте додаткове відкрите вікно для кожної виконаної команди. sleep 60В кінці є , щоб тримати .commandфайли навколо під час їх виконання. В іншому випадку оболонка завершується занадто швидко, виконуючи пастку для видалення тимчасової директорії (створеної mktemp), перш ніж запущені сеанси отримають можливість читати файли.


0

Ви також можете викликати нову командну функцію терміналу, натиснувши Shift + ⌘ + Nкомбінацію клавіш. Команда, яку ви введете у поле, буде виконана у новому вікні терміналу.


Звичайно, корисно знати, але мені це потрібно робити програмно. Якщо моя програма згенерує файл .command, а потім відкриє, це розумне (якщо трохи хакерське) рішення.
Walt D

0

Я називаю цей сценарій trun. Я пропоную помістити його в каталог у вашому виконуваному шляху. Переконайтеся, що він виконується таким чином:

chmod +x ~/bin/trun

Тоді ви можете запускати команди в новому вікні, просто додавши trun перед ними, наприклад:

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

Ось сценарій. Він робить деякі вигадливі речі, наприклад, передає ваші аргументи, змінює рядок заголовка, очищає екран, щоб усунути безлад запуску оболонки, видалити його файл, коли це буде зроблено. Використовуючи унікальний файл для кожного нового вікна, його можна використовувати для створення багатьох вікон одночасно.

#!/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

1
Неправильне використання $*в цілому призведе до поразки будь-якого нетривіального цитування у введенні. Ви хочете "$@"замість цього.
триплі

Я шукав open -b com.apple.terminal. Дякую
Ебру Єнер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.