Відкрити нову вкладку Terminal з командного рядка (Mac OS X)


116

Чи можливо відкрити нову вкладку в терміналі Mac OS X з командного рядка в щойно відкритій вкладці?

Я знаю, що комбінація клавіш для відкриття нової вкладки в терміналі - "CMD + t", але я шукаю рішення на основі сценарію, виконане в командному рядку.

Відповіді:


126

Спробуйте це:

osascript -e 'tell application "Terminal" to activate' -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down'

D'Oh! Я пропустив ваш коментар повністю, знайшов подібне рішення через google. Одна відмінність: для мене це не спрацювало (10.6.8), якщо Terminal не був передовим додатком, тому я додав "активувати", щоб змусити його перейти на фронт.
Гордон Девіссон

5
редагувати: Як я можу вставити нову команду ex echo helloна цю нову вкладку.
ThomasReggi

22
@ThomasReggi: додайте -e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'до кінця команду osascript.
Гордон Девіссон

2
@clevertension для iTerm це простоopen -a iTerm ~/Applications/
onmyway133

1
@Ciastopiekarz Ви маєте на увазі щойно відкриту вкладку? Використовуйте той самий підхід, що і моя відповідь до ThomasReggi: дод -e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'. Зауважте, що якщо шлях йде від змінної, вам потрібно буде використовувати рядок з подвійним котируванням замість одноцитованих і уникати внутрішньої котируемой рядка, і, ймовірно, самого шляху.
Гордон Девіссон

163

Оновлення : ця відповідь набула популярності на основі функції оболонки, розміщеної нижче, яка все ще працює як OSX 10.10 (за винятком -gопції).
Однак у реєстрі npm як CLI тепер доступна більш повнофункціональна, більш надійна перевірена версія сценарію , яка також підтримує iTerm2 :ttab

  • Якщо у вас встановлений Node.js , просто запустіть:

    npm install -g ttab
    

    (залежно від того, як ви встановили Node.js, можливо, вам доведеться зробити попередній запис sudo).

  • В іншому випадку дотримуйтесь цих інструкцій .

  • Після встановлення запустіть ttab -hдля отримання короткої інформації про використання або man ttabдля перегляду посібника.


Спираючись на прийняту відповідь, нижче наведена функція зручності для відкриття нової вкладки в поточному вікні терміналу та необов'язково виконання команди (як бонус, замість цього є варіант функції для створення нового вікна ).

Якщо вказана команда, її перший маркер буде використаний як заголовок нової вкладки.

Зразки викликів:

    # Get command-line help.
newtab -h
    # Simpy open new tab.
newtab
    # Open new tab and execute command (quoted parameters are supported).
newtab ls -l "$Home/Library/Application Support"
    # Open a new tab with a given working directory and execute a command;
    # Double-quote the command passed to `eval` and use backslash-escaping inside.
newtab eval "cd ~/Library/Application\ Support; ls"
    # Open new tab, execute commands, close tab.
newtab eval "ls \$HOME/Library/Application\ Support; echo Press a key to exit.; read -s -n 1; exit"
    # Open new tab and execute script.
newtab /path/to/someScript
    # Open new tab, execute script, close tab.
newtab exec /path/to/someScript
    # Open new tab and execute script, but don't activate the new tab.
newtab -G /path/to/someScript

CAVEAT : При запуску newtab(або newwin) зі сценарію, скрипт початкової робоча папка буде робочої папка в новій вкладці / вікні, навіть якщо змінити робочу папку всередині сценарію , перш ніж посилатися newtab/ newwin- пройти evalз cdкомандою в якості обхідного (див. приклад вище).

Вихідний код (наприклад, вставте у свій профіль bash):

# Opens a new tab in the current Terminal window and optionally executes a command.
# When invoked via a function named 'newwin', opens a new Terminal *window* instead.
function newtab {

    # If this function was invoked directly by a function named 'newwin', we open a new *window* instead
    # of a new tab in the existing window.
    local funcName=$FUNCNAME
    local targetType='tab'
    local targetDesc='new tab in the active Terminal window'
    local makeTab=1
    case "${FUNCNAME[1]}" in
        newwin)
            makeTab=0
            funcName=${FUNCNAME[1]}
            targetType='window'
            targetDesc='new Terminal window'
            ;;
    esac

    # Command-line help.
    if [[ "$1" == '--help' || "$1" == '-h' ]]; then
        cat <<EOF
Synopsis:
    $funcName [-g|-G] [command [param1 ...]]

Description:
    Opens a $targetDesc and optionally executes a command.

    The new $targetType will run a login shell (i.e., load the user's shell profile) and inherit
    the working folder from this shell (the active Terminal tab).
    IMPORTANT: In scripts, \`$funcName\` *statically* inherits the working folder from the
    *invoking Terminal tab* at the time of script *invocation*, even if you change the
    working folder *inside* the script before invoking \`$funcName\`.

    -g (back*g*round) causes Terminal not to activate, but within Terminal, the new tab/window
      will become the active element.
    -G causes Terminal not to activate *and* the active element within Terminal not to change;
      i.e., the previously active window and tab stay active.

    NOTE: With -g or -G specified, for technical reasons, Terminal will still activate *briefly* when
    you create a new tab (creating a new window is not affected).

    When a command is specified, its first token will become the new ${targetType}'s title.
    Quoted parameters are handled properly.

    To specify multiple commands, use 'eval' followed by a single, *double*-quoted string
    in which the commands are separated by ';' Do NOT use backslash-escaped double quotes inside
    this string; rather, use backslash-escaping as needed.
    Use 'exit' as the last command to automatically close the tab when the command
    terminates; precede it with 'read -s -n 1' to wait for a keystroke first.

    Alternatively, pass a script name or path; prefix with 'exec' to automatically
    close the $targetType when the script terminates.

Examples:
    $funcName ls -l "\$Home/Library/Application Support"
    $funcName eval "ls \\\$HOME/Library/Application\ Support; echo Press a key to exit.; read -s -n 1; exit"
    $funcName /path/to/someScript
    $funcName exec /path/to/someScript
EOF
        return 0
    fi

    # Option-parameters loop.
    inBackground=0
    while (( $# )); do
        case "$1" in
            -g)
                inBackground=1
                ;;
            -G)
                inBackground=2
                ;;
            --) # Explicit end-of-options marker.
                shift   # Move to next param and proceed with data-parameter analysis below.
                break
                ;;
            -*) # An unrecognized switch.
                echo "$FUNCNAME: PARAMETER ERROR: Unrecognized option: '$1'. To force interpretation as non-option, precede with '--'. Use -h or --h for help." 1>&2 && return 2
                ;;
            *)  # 1st argument reached; proceed with argument-parameter analysis below.
                break
                ;;
        esac
        shift
    done

    # All remaining parameters, if any, make up the command to execute in the new tab/window.

    local CMD_PREFIX='tell application "Terminal" to do script'

        # Command for opening a new Terminal window (with a single, new tab).
    local CMD_NEWWIN=$CMD_PREFIX    # Curiously, simply executing 'do script' with no further arguments opens a new *window*.
        # Commands for opening a new tab in the current Terminal window.
        # Sadly, there is no direct way to open a new tab in an existing window, so we must activate Terminal first, then send a keyboard shortcut.
    local CMD_ACTIVATE='tell application "Terminal" to activate'
    local CMD_NEWTAB='tell application "System Events" to keystroke "t" using {command down}'
        # For use with -g: commands for saving and restoring the previous application
    local CMD_SAVE_ACTIVE_APPNAME='tell application "System Events" to set prevAppName to displayed name of first process whose frontmost is true'
    local CMD_REACTIVATE_PREV_APP='activate application prevAppName'
        # For use with -G: commands for saving and restoring the previous state within Terminal
    local CMD_SAVE_ACTIVE_WIN='tell application "Terminal" to set prevWin to front window'
    local CMD_REACTIVATE_PREV_WIN='set frontmost of prevWin to true'
    local CMD_SAVE_ACTIVE_TAB='tell application "Terminal" to set prevTab to (selected tab of front window)'
    local CMD_REACTIVATE_PREV_TAB='tell application "Terminal" to set selected of prevTab to true'

    if (( $# )); then # Command specified; open a new tab or window, then execute command.
            # Use the command's first token as the tab title.
        local tabTitle=$1
        case "$tabTitle" in
            exec|eval) # Use following token instead, if the 1st one is 'eval' or 'exec'.
                tabTitle=$(echo "$2" | awk '{ print $1 }') 
                ;;
            cd) # Use last path component of following token instead, if the 1st one is 'cd'
                tabTitle=$(basename "$2")
                ;;
        esac
        local CMD_SETTITLE="tell application \"Terminal\" to set custom title of front window to \"$tabTitle\""
            # The tricky part is to quote the command tokens properly when passing them to AppleScript:
            # Step 1: Quote all parameters (as needed) using printf '%q' - this will perform backslash-escaping.
        local quotedArgs=$(printf '%q ' "$@")
            # Step 2: Escape all backslashes again (by doubling them), because AppleScript expects that.
        local cmd="$CMD_PREFIX \"${quotedArgs//\\/\\\\}\""
            # Open new tab or window, execute command, and assign tab title.
            # '>/dev/null' suppresses AppleScript's output when it creates a new tab.
        if (( makeTab )); then
            if (( inBackground )); then
                # !! Sadly, because we must create a new tab by sending a keystroke to Terminal, we must briefly activate it, then reactivate the previously active application.
                if (( inBackground == 2 )); then # Restore the previously active tab after creating the new one.
                    osascript -e "$CMD_SAVE_ACTIVE_APPNAME" -e "$CMD_SAVE_ACTIVE_TAB" -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" -e "$cmd in front window" -e "$CMD_SETTITLE" -e "$CMD_REACTIVATE_PREV_APP" -e "$CMD_REACTIVATE_PREV_TAB" >/dev/null
                else
                    osascript -e "$CMD_SAVE_ACTIVE_APPNAME" -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" -e "$cmd in front window" -e "$CMD_SETTITLE" -e "$CMD_REACTIVATE_PREV_APP" >/dev/null
                fi
            else
                osascript -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" -e "$cmd in front window" -e "$CMD_SETTITLE" >/dev/null
            fi
        else # make *window*
            # Note: $CMD_NEWWIN is not needed, as $cmd implicitly creates a new window.
            if (( inBackground )); then
                # !! Sadly, because we must create a new tab by sending a keystroke to Terminal, we must briefly activate it, then reactivate the previously active application.
                if (( inBackground == 2 )); then # Restore the previously active window after creating the new one.
                    osascript -e "$CMD_SAVE_ACTIVE_WIN" -e "$cmd" -e "$CMD_SETTITLE" -e "$CMD_REACTIVATE_PREV_WIN" >/dev/null
                else
                    osascript -e "$cmd" -e "$CMD_SETTITLE" >/dev/null
                fi
            else
                    # Note: Even though we do not strictly need to activate Terminal first, we do it, as assigning the custom title to the 'front window' would otherwise sometimes target the wrong window.
                osascript -e "$CMD_ACTIVATE" -e "$cmd" -e "$CMD_SETTITLE" >/dev/null
            fi
        fi        
    else    # No command specified; simply open a new tab or window.
        if (( makeTab )); then
            if (( inBackground )); then
                # !! Sadly, because we must create a new tab by sending a keystroke to Terminal, we must briefly activate it, then reactivate the previously active application.
                if (( inBackground == 2 )); then # Restore the previously active tab after creating the new one.
                    osascript -e "$CMD_SAVE_ACTIVE_APPNAME" -e "$CMD_SAVE_ACTIVE_TAB" -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" -e "$CMD_REACTIVATE_PREV_APP" -e "$CMD_REACTIVATE_PREV_TAB" >/dev/null
                else
                    osascript -e "$CMD_SAVE_ACTIVE_APPNAME" -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" -e "$CMD_REACTIVATE_PREV_APP" >/dev/null
                fi
            else
                osascript -e "$CMD_ACTIVATE" -e "$CMD_NEWTAB" >/dev/null
            fi
        else # make *window*
            if (( inBackground )); then
                # !! Sadly, because we must create a new tab by sending a keystroke to Terminal, we must briefly activate it, then reactivate the previously active application.
                if (( inBackground == 2 )); then # Restore the previously active window after creating the new one.
                    osascript -e "$CMD_SAVE_ACTIVE_WIN" -e "$CMD_NEWWIN" -e "$CMD_REACTIVATE_PREV_WIN" >/dev/null
                else
                    osascript -e "$CMD_NEWWIN" >/dev/null
                fi
            else
                    # Note: Even though we do not strictly need to activate Terminal first, we do it so as to better visualize what is happening (the new window will appear stacked on top of an existing one).
                osascript -e "$CMD_ACTIVATE" -e "$CMD_NEWWIN" >/dev/null
            fi
        fi
    fi

}

# Opens a new Terminal window and optionally executes a command.
function newwin {
    newtab "$@" # Simply pass through to 'newtab', which will examine the call stack to see how it was invoked.
}

3
@jcollum Моє задоволення; рада, що ви вважаєте його корисним. Я щойно оновив публікацію з попередньою робочою папкою, а також оновив код: додав параметри -g(не активуйте термінал під час створення нової вкладки / вікна) та -G(не активуйте термінал і не змінюйте активну вкладку всередині терміналу ) - корисна, наприклад, при запуску сервера у фоновому режимі. Зауважте, що створюючи нову вкладку таким чином, термінал все ще потрібно коротко активувати, перш ніж активована раніше активна програма.
mklement0

1
@Leonardo Нова вкладка має таку ж робочу директорію, що і вкладка, з якої викликалася функція. Перехід до іншої папки всередині сценарію перед викликом newtab, на жаль, НЕ працює. Вирішення завдання полягає у передачі evalзаяви із cdкомандою до newtab; наприклад: newtab eval "cd ~/Library/Application\ Support; ls". Подвійне цитування всієї команди, переданої до цього eval, і використання зворотної косої риси всередині.
mklement0

1
@ IntegrityFirst: За вашою пропозицією я переключив підписи функцій на function newtabта function newwin(однак, немає дужок), щоб уникнути зіткнення з псевдонімами при визначенні функцій, але зауважте, що при виклику псевдонім з таким же ім’ям має перевагу (на обійти псевдонім, ad-hoc, цитувати будь-яку частину назви функції, наприклад:) \newtab.
mklement0

2
@ IntegrityFirst: Ось, що я дізнався: Використання <name>() { ... }синтаксису функції POSIX робить <name>предметом розширення псевдонім , який порушує визначення функції (помилка розбору!), Якщо псевдонім <name>буде визначений. Зазвичай це не викликає занепокоєння, оскільки у звичайно викликаних сценаріях псевдонім розширення вимкнено за замовчуванням. Однак у скриптах, ЗАПИСАНИХ із ІНТЕРАКТИВНОЇ оболонки - наприклад, у файлах профілю / ініціалізації - включено Псевдонім розширення. Виправлення: Використовуйте function <name> { ... } синтаксис non-POSIX для визначення функції - <name>тоді НЕ підлягає розширенню псевдоніму.
mklement0

1
Дякую! до цього додається if [ "${BASH_SOURCE}" == "${0}" ]випадок справи, тому його можна назвати як сценарій (наприклад newtab.sh, newwin.sh): gist.github.com/westurner/01b6be85e5a51fda22a6
Уес Тернер

18

Ось як це робиться bash_it :

function tab() {
  osascript 2>/dev/null <<EOF
    tell application "System Events"
      tell process "Terminal" to keystroke "t" using command down
    end
    tell application "Terminal"
      activate
      do script with command "cd \"$PWD\"; $*" in window 1
    end tell
EOF
}

Додавши це до свого .bash_profile, ви будете використовувати tab командою, щоб відкрити поточну робочу директорію на новій вкладці.

Дивіться: https://github.com/revans/bash-it/blob/master/plugins/available/osx.plugin.bash#L3


1
Дуже корисний. Використовуючи це у своєму .bash_profile, я можу запустити купу вкладок і ssh автоматично до них. Звичайно, у мене ввімкнена автентифікація пари ключів ssh
Sandeep Kanabar

16
osascript -e 'tell app "Terminal"
   do script "echo hello"
end tell'

Це відкриває новий термінал і виконує команду "echo hello" всередині нього.


3
Це спрацювало, але нова вкладка була створена в окремому екземплярі Terminal. Чи все-таки нова вкладка залишається в поточному екземплярі мого терміналу?
Calvin Cheng

До речі, ви можете використовувати do script ""з порожнім рядком для створення нового терміналу без видачі команди.
Кріс Пейдж

9

Якщо ви використовуєте oh-my-zsh (яким повинен користуватися кожен модний гек), після активації плагіна "osx" .zshrcпросто введіть tabкоманду; це відкриє нову вкладку і cdв каталозі, в якому ви знаходилися.


Це виглядає дуже цікаво. Яка різниця між zcsh і звичайним bash?
Calvin Cheng

Вони дуже схожі, але найцікавіше, що він має інтелектуальне, потужне заповнення вкладок та автоматичне виправлення. Дивіться хороше порівняння тут . Oh-my-zsh створює обстановку із приємними та зручними налаштуваннями / плагінами, щоб розпочати роботу
CharlesB

Швидко перегляньте посилання порівняння CharlesB. Дуже цікаво. Звучить майже як оболонка BPython проти оболонки iPython.
Calvin Cheng

zsh вдається утримати ще більше старого валу, щоб втратити контроль
Джеймс

Чи можете ви надати більше інформації щодо цього? Що таке команда вкладок? Введення tabне виникає нічого робити
Solvitieg

7

Комбінація клавіш cmd-tвідкриває нову вкладку, тому ви можете передати цю клавішу команді OSA наступним чином:

osascript -e 'tell application "System Events"' -e 'keystroke "t" using command down' -e 'end tell'


6

Я додав їх до свого .bash_profile, щоб я мав доступ до імені табуляції та newtab

tabname() {
  printf "\e]1;$1\a"
}

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
}

Тож, коли ви перебуваєте на певній вкладці, ви можете просто ввести

tabname "New TabName"

щоб організувати всі відкриті вкладки. Це набагато краще, ніж отримувати інформацію на вкладці та змінювати її там.


Дякую. чи знаєте ви, як зберегти ім'я вкладки після того, як я зроблю ssh з вкладки та вийду з сеансу ssh?
anjanb

4

Я знаю, що це старий пост, але це працювало для мене:

open -a Terminal "`pwd`"

Для запуску команди, як вимагається нижче, потрібні певні джиггери:

echo /sbin/ping 8.8.8.8 > /tmp/tmp.sh;chmod a+x /tmp/tmp.sh;open -a Terminal /tmp/tmp.sh

Дуже хороша! Як мені це зробити, якщо я хочу передавати команди, які будуть запускатися в новому екземплярі Terminal? : D
Стразан

@Strazan редагував відповідь вище ... весело !! Схоже, термінал прийме такий параметр ...
неофіт

3

коли ви знаходитесь у вікні терміналу, команда + n => відкриває новий термінал, а команда + t => відкриває нову вкладку у поточному вікні терміналу


1
це має працювати з командного рядка. в основному сценарій. бо це повторюване завдання
Джанфранко П.

2

Якщо ви використовуєте iTerm, ця команда відкриє нову вкладку:

osascript -e 'tell application "iTerm" to activate' -e 'tell application "System Events" to tell process "iTerm" to keystroke "t" using command down'

Якщо вам потрібно додати це до .zshrc або .bashrc, ви можете зробити це за допомогою функції замість псевдоніму (через те, що всі втечі вам доведеться зробити). stackoverflow.com/a/20111135/1401336
Vigrant

@Andrew Schreiber: Але управління не переноситься на нову вкладку. Я маю на увазі, якщо після відкриття нової вкладки у вас є якийсь код, цей код виконується в оригінальній вкладці. Чи є спосіб сказати сценарію обробляти наступні команди на новій вкладці?
Ashwin


0

Як щодо цього простого фрагмента, заснованого на стандартній команді скрипту (ехо):

# set mac osx's terminal title to "My Title"
echo -n -e "\033]0;My Title\007"

0

Якщо встановлено X (наприклад, з домашнього або кварцового), простий "xterm &" робить (майже) трюк, він відкриває нове вікно терміналу (однак не вкладку).

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