Buka Tab Terminal baru dari baris perintah (Mac OS X)

116

Apakah mungkin untuk membuka tab baru di terminal Mac OS X dari baris perintah di tab yang sedang dibuka?

Saya tahu bahwa pintasan keyboard untuk membuka tab baru di Terminal adalah "CMD + t" tetapi saya mencari solusi berbasis skrip yang dijalankan di baris perintah.

Calvin Cheng
sumber

Jawaban:

126

Coba ini:

osascript -e 'tell application "Terminal" to activate' -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down'
Gordon Davisson
sumber
D'Oh! Saya melewatkan komentar Anda sepenuhnya, menemukan solusi serupa melalui google. Satu perbedaan: itu tidak berhasil untuk saya (pada 10.6.8) kecuali Terminal adalah aplikasi paling depan, jadi saya menambahkan "aktifkan" untuk memaksanya ke depan.
Gordon Davisson
5
edit: Bagaimana cara memasukkan perintah baru ex echo helloke tab baru ini.
ThomasReggi
22
@ThomasReggi: Tambahkan -e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'ke akhir perintah osascript.
Gordon Davisson
2
@clevertension untuk iTerm itu hanyaopen -a iTerm ~/Applications/
onmyway133
1
@Ciastopiekarz Yang Anda maksud di tab yang baru dibuka? Gunakan pendekatan yang sama sebagai jawaban saya untuk ThomasReggi: tambahkan -e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'. Perhatikan bahwa jika jalur berasal dari variabel, Anda harus menggunakan string yang dikutip ganda, bukan kutipan tunggal, dan keluar dari string yang dikutip dalam, dan mungkin jalur itu sendiri.
Gordon Davisson
163

Pembaruan : Jawaban ini mendapatkan popularitas berdasarkan fungsi shell yang diposting di bawah ini, yang masih berfungsi pada OSX 10.10 (dengan pengecualian -gopsi).
Namun, versi skrip yang lebih lengkap, lebih kuat, dan teruji sekarang tersedia di registri npm sebagai CLIttab , yang juga mendukung iTerm2 :

  • Jika Anda menginstal Node.js , jalankan saja:

    npm install -g ttab
    

    (tergantung bagaimana Anda menginstal Node.js, Anda mungkin harus menambahkannya sudo).

  • Jika tidak, ikuti petunjuk ini .

  • Setelah terinstal, jalankan ttab -huntuk informasi penggunaan yang ringkas, atau man ttabuntuk melihat manual.


Berdasarkan jawaban yang diterima, di bawah ini adalah fungsi kenyamanan bash untuk membuka tab baru di jendela Terminal saat ini dan secara opsional menjalankan perintah (sebagai bonus, ada fungsi varian untuk membuat jendela baru sebagai gantinya).

Jika sebuah perintah ditentukan, token pertamanya akan digunakan sebagai judul tab baru.

Contoh doa:

    # 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

PERHATIAN : Saat Anda menjalankan newtab(atau newwin) dari skrip, folder kerja awal skrip akan menjadi folder kerja di tab / jendela baru, bahkan jika Anda mengubah folder kerja di dalam skrip sebelum memanggil newtab/ newwin- lewati evaldengan cdperintah sebagai solusinya (lihat contoh di atas).

Kode sumber (rekatkan ke profil bash Anda, misalnya):

# 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.
}
mklement0
sumber
3
@jollum Dengan senang hati; senang Anda menganggapnya berguna. Saya baru saja memperbarui posting dengan folder peringatan yang berfungsi dan juga memperbarui kode: opsi yang ditambahkan -g(jangan aktifkan Terminal saat membuat tab / jendela baru) dan -G(jangan aktifkan Terminal dan jangan ubah tab aktif di dalam Terminal ) - membantu, misalnya, saat memulai server di latar belakang. Perhatikan bahwa saat membuat tab baru dengan cara ini, Terminal masih harus diaktifkan sebentar sebelum aplikasi yang sebelumnya aktif diaktifkan kembali.
mklement0
1
@Leonardo Tab baru memiliki direktori kerja yang sama dengan tab tempat fungsi tersebut dipanggil. newtabSayangnya, mengubah ke folder lain di dalam skrip sebelum memanggil TIDAK berfungsi. Solusinya adalah dengan mengirimkan evalpernyataan dengan cdperintah ke newtab; mis newtab eval "cd ~/Library/Application\ Support; ls". : . Kutip dua kali seluruh perintah yang diteruskan eval, dan gunakan backslash-escaping di dalamnya.
mklement0
1
@IntegrityFirst: Sesuai saran Anda, saya telah mengalihkan tanda tangan fungsi ke function newtabdan function newwin(namun, TIDAK ADA tanda kurung), sehingga harus menghindari tabrakan dengan alias saat mendefinisikan fungsi, tetapi perhatikan bahwa saat pemanggilan, alias dengan nama yang sama diutamakan (untuk lewati alias, ad-hoc, kutip bagian mana pun dari nama fungsi, misalnya:) \newtab.
mklement0
2
@IntegrityFirst: Inilah yang saya pelajari: Menggunakan <name>() { ... }sintaks fungsi POSIX membuat <name>subjek untuk ekspansi alias , yang mematahkan definisi fungsi (kesalahan penguraian!) Jika sebuah alias <name>kebetulan didefinisikan. Biasanya tidak menjadi perhatian, karena dalam skrip yang biasanya dipanggil, perluasan alias dimatikan secara default. Namun, dalam skrip yang DIBERIKAN dari shell INTERAKTIF - seperti di file profil / inisialisasi - perluasan alias IS diaktifkan. Fix: Gunakan function <name> { ... } sintaks non-POSIX untuk menentukan fungsi - <name>maka TIDAK tunduk pada ekspansi alias.
mklement0
1
Terima kasih! ini menambahkan pernyataan if [ "${BASH_SOURCE}" == "${0}" ]with case sehingga dapat disebut sebagai skrip (misalnya newtab.sh, newwin.sh): gist.github.com/westurner/01b6be85e5a51fda22a6
Wes Turner
18

Inilah cara melakukannya oleh 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
}

Setelah menambahkan ini ke .bash_profile Anda, Anda akan menggunakan tabperintah untuk membuka direktori kerja saat ini di tab baru.

Lihat: https://github.com/revans/bash-it/blob/master/plugins/available/osx.plugin.bash#L3

dleavitt
sumber
1
Sangat membantu. Menggunakan ini di .bash_profile saya, saya dapat meluncurkan banyak tab dan ssh ke sana secara otomatis. Tentu saja, saya telah mengaktifkan otentikasi pasangan kunci ssh
Sandeep Kanabar
16
osascript -e 'tell app "Terminal"
   do script "echo hello"
end tell'

Ini membuka terminal baru dan menjalankan perintah "echo hello" di dalamnya.

Szymon Morawski
sumber
3
Ini berfungsi tetapi tab baru dibuat dalam contoh terpisah dari Terminal. Apakah tetap ada tab baru yang tetap ada di contoh Terminal saya saat ini?
Calvin Cheng
Ngomong-ngomong, Anda dapat menggunakan do script ""string kosong untuk membuat terminal baru tanpa mengeluarkan perintah.
Chris Halaman
9

Jika Anda menggunakan oh-my-zsh (yang harus digunakan setiap geek trendi), setelah mengaktifkan plugin "osx" .zshrc, cukup masukkan tabperintah; itu akan membuka tab baru dan cddi direktori tempat Anda berada.

CharlesB
sumber
Ini terlihat sangat menarik. Apa perbedaan antara zcsh dan bash konvensional?
Calvin Cheng
Keduanya sangat mirip, tetapi yang paling menarik adalah penyelesaian tab yang cerdas dan kuat serta koreksi otomatis. Lihat perbandingan yang bagus di sini . Oh-my-zsh mengatur lingkungan dengan pengaturan / plugin yang bagus dan praktis untuk Anda mulai
CharlesB
Lihat sekilas tautan perbandingan CharlesB. Sangat menarik. Kedengarannya hampir seperti shell BPython versus shell iPython.
Calvin Cheng
zsh berhasil menjaga lebih banyak cruft tua untuk kehilangan kendali
James
Bisakah Anda memberikan informasi lebih lanjut tentang ini? Apa itu perintah tab? Masuk tabtampaknya tidak melakukan apa
Solvitieg
7

Pintasan keyboard cmd-tmembuka tab baru, sehingga Anda dapat meneruskan penekanan tombol ini ke perintah OSA sebagai berikut:

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

Aziz Alto
sumber
6

Saya menambahkan ini ke .bash_profile saya sehingga saya dapat memiliki akses ke nama tab dan tab baru

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
}

Jadi saat Anda berada di tab tertentu, Anda cukup mengetik

tabname "New TabName"

untuk mengatur semua tab terbuka yang Anda miliki. Ini jauh lebih baik daripada mendapatkan info di tab dan mengubahnya di sana.

richtera
sumber
Terima kasih. tahukah Anda cara mempertahankan nama tab setelah saya melakukan ssh dari tab dan keluar dari sesi ssh?
anjanb
4

Saya tahu ini adalah posting lama, tetapi ini berhasil untuk saya:

open -a Terminal "`pwd`"

Untuk menjalankan perintah seperti yang diminta di bawah ini, diperlukan beberapa jiggery:

echo /sbin/ping 8.8.8.8 > /tmp/tmp.sh;chmod a+x /tmp/tmp.sh;open -a Terminal /tmp/tmp.sh
neophytte.dll
sumber
Sangat bagus! Bagaimana saya melakukannya jika saya ingin memberikan perintah yang akan dijalankan di terminal baru? : D
Strazan
@Strazan mengedit jawaban di atas ... selamat bersenang-senang !! Sepertinya terminal akan mengambil parameter seperti itu ...
neophytte
3

ketika Anda berada di jendela terminal, perintah + n => membuka terminal baru dan perintah + t => membuka tab baru di jendela terminal saat ini

xdev
sumber
1
ini harus bekerja dari baris perintah. pada dasarnya sebuah naskah. karena ini adalah tugas yang berulang
Gianfranco P.
2

Jika Anda menggunakan iTerm , perintah ini akan membuka tab baru:

osascript -e 'tell application "iTerm" to activate' -e 'tell application "System Events" to tell process "iTerm" to keystroke "t" using command down'
Andrew Schreiber
sumber
Jika Anda perlu menambahkan ini ke .zshrc atau .bashrc Anda dapat melakukannya dengan sebuah fungsi alih-alih alias (karena semua pelolosan pada akhirnya harus Anda lakukan). stackoverflow.com/a/20111135/1401336
Vigrant
@ Andrew Schreiber: Tetapi kontrol tidak ditransfer ke tab baru. Maksud saya, jika Anda memiliki beberapa kode setelah membuka tab baru, kode itu dijalankan di tab asli. Apakah ada cara untuk memberi tahu skrip untuk memproses perintah berikut di tab baru?
Ashwin
1
open -n -a Terminal

dan Anda dapat meneruskan direktori target sebagai parameter

open -n -a Terminal /Users
Everton Santos
sumber
Ini membuka jendela baru untuk saya. Bukan tab.
stack-delay
0

Bagaimana dengan cuplikan sederhana ini, berdasarkan perintah skrip standar (echo):

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

Dengan X terinstal (misalnya dari homebrew, atau Quartz), "xterm &" sederhana melakukan (hampir) trik, ini membuka jendela terminal baru (meskipun bukan tab).

Immanuel Kant
sumber