Mở Tab đầu cuối mới từ dòng lệnh (Mac OS X)


116

Có thể mở tab mới trong thiết bị đầu cuối của Mac OS X từ dòng lệnh trong tab đang mở không?

Tôi biết rằng phím tắt để mở tab mới trong Terminal là "CMD + t" nhưng tôi đang tìm kiếm giải pháp dựa trên tập lệnh được thực thi trong dòng lệnh.

Câu trả lời:


126

Thử cái này:

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

D'Oh! Tôi đã bỏ lỡ bình luận của bạn hoàn toàn, tìm thấy một giải pháp tương tự thông qua google. Một điểm khác biệt: nó không hoạt động với tôi (vào ngày 10.6.8) trừ khi Terminal là ứng dụng hàng đầu, vì vậy tôi đã thêm "kích hoạt" để buộc nó lên phía trước.
Gordon Davisson

5
chỉnh sửa: Làm cách nào để tôi đặt một lệnh mới cũ echo hellovào tab mới này.
ThomasReggi

22
@ThomasReggi: Thêm -e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'vào cuối lệnh osascript.
Gordon Davisson

2
@clevertension cho iTerm nó chỉ làopen -a iTerm ~/Applications/
onmyway133

1
@Ciastopiekarz Ý của bạn là trong tab mới mở? Sử dụng cách tiếp cận tương tự như câu trả lời của tôi cho ThomasReggi: thêm -e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'. Lưu ý rằng nếu đường dẫn đến từ một biến, bạn sẽ cần sử dụng một chuỗi được trích dẫn kép thay vì được trích dẫn đơn và thoát khỏi chuỗi được trích dẫn bên trong có thể là chính đường dẫn đó.
Gordon Davisson

163

Cập nhật : Câu trả lời này đã trở nên phổ biến dựa trên hàm shell được đăng bên dưới, hàm này vẫn hoạt động như OSX 10.10 (ngoại trừ -gtùy chọn).
Tuy nhiên, phiên bản script đã được thử nghiệm đầy đủ tính năng hơn, mạnh mẽ hơn hiện có sẵn tại sổ đăng ký npm dưới dạng CLIttab , cũng hỗ trợ iTerm2 :

  • Nếu bạn đã cài đặt Node.js , chỉ cần chạy:

    npm install -g ttab
    

    (tùy thuộc vào cách bạn cài đặt Node.js, bạn có thể phải thêm trước sudo).

  • Nếu không, hãy làm theo các hướng dẫn sau .

  • Sau khi cài đặt, hãy chạy ttab -hđể biết thông tin sử dụng ngắn gọn hoặc man ttabđể xem hướng dẫn sử dụng.


Dựa trên câu trả lời được chấp nhận, bên dưới là một chức năng tiện lợi cơ bản để mở một tab mới trong cửa sổ Terminal hiện tại và tùy chọn thực hiện một lệnh (như một phần thưởng, có một hàm biến thể để tạo một cửa sổ mới thay thế).

Nếu một lệnh được chỉ định, mã thông báo đầu tiên của nó sẽ được sử dụng làm tiêu đề của tab mới.

Lời kêu gọi mẫu:

    # 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 : Khi bạn chạy newtab(hoặc newwin) từ một tập lệnh, thư mục làm việc ban đầu của tập lệnh sẽ là thư mục làm việc trong tab / cửa sổ mới, ngay cả khi bạn thay đổi thư mục làm việc bên trong tập lệnh trước khi gọi newtab/ newwin- truyền evalbằng cdlệnh như một giải pháp thay thế (xem ví dụ trên).

Mã nguồn (ví dụ: dán vào hồ sơ bash của bạn):

# 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 Niềm vui của tôi; rất vui vì bạn thấy nó hữu ích. Tôi vừa cập nhật bài đăng với các thư mục đang hoạt động báo trước và cũng cập nhật mã: thêm tùy chọn -g(không kích hoạt Terminal khi tạo tab / cửa sổ mới) và -G(không kích hoạt Terminal không thay đổi tab đang hoạt động bên trong Terminal ) - hữu ích, ví dụ, khi khởi động một máy chủ trong nền. Lưu ý rằng khi tạo tab mới theo cách này, Terminal vẫn phải được kích hoạt trong thời gian ngắn trước khi ứng dụng đã hoạt động trước đó được kích hoạt lại.
mklement0

1
@Leonardo Tab mới có cùng thư mục làm việc với tab mà từ đó hàm được gọi. newtabRất tiếc, việc thay đổi sang một thư mục khác bên trong tập lệnh trước khi gọi KHÔNG hoạt động. Cách giải quyết là chuyển một evalcâu lệnh với một cdlệnh tới newtab; ví dụ: newtab eval "cd ~/Library/Application\ Support; ls". Trích dẫn kép toàn bộ lệnh được chuyển đến evalvà sử dụng dấu gạch chéo ngược thoát bên trong.
mklement0

1
@IntegrityFirst: Theo gợi ý của bạn, tôi đã chuyển chữ ký hàm thành function newtabfunction newwin(tuy nhiên, KHÔNG có dấu ngoặc đơn), do đó sẽ tránh va chạm với bí danh khi xác định các hàm, nhưng lưu ý rằng khi gọi, bí danh cùng tên sẽ được ưu tiên (để bỏ qua bí danh, đặc biệt, trích dẫn bất kỳ phần nào của tên hàm, ví dụ \newtab:).
mklement0

2
@IntegrityFirst: Đây là những gì tôi đã học: Sử dụng POSIX <name>() { ... }chức năng cú pháp làm <name>đối tượng để mở rộng bí danh , mà phá vỡ định nghĩa hàm nếu một bí danh (phân tích lỗi!) <name>Xảy ra được xác định. Thông thường không phải là mối quan tâm, vì trong mở rộng bí danh tập lệnh được gọi thông thường bị TẮT theo mặc định. Tuy nhiên, trong các tập lệnh SOURCED từ trình bao TƯƠNG TÁC - chẳng hạn như trong các tệp hồ sơ / khởi tạo - đã bật tính năng mở rộng bí danh. Khắc phục: Sử dụng function <name> { ... } cú pháp không phải POSIX để xác định hàm - <name>sau đó KHÔNG phải mở rộng bí danh.
mklement0

1
Cảm ơn! này cho biết thêm một if [ "${BASH_SOURCE}" == "${0}" ]với một tuyên bố trường hợp để nó có thể được gọi là một kịch bản (ví dụ newtab.sh, newwin.sh): gist.github.com/westurner/01b6be85e5a51fda22a6
Wes Turner

18

Đây là cách nó được thực hiện bởi 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
}

Sau khi thêm cái này vào .bash_profile của bạn, bạn sẽ sử dụng tablệnh để mở thư mục làm việc hiện tại trong một tab mới.

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


1
Rất hữu ích. Sử dụng điều này trong .bash_profile của tôi, tôi có thể khởi chạy một loạt các tab và ssh đến chúng một cách tự động. Tất nhiên, tôi đã ssh authentication key-cặp kích hoạt
Sandeep Kanabar

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

Thao tác này sẽ mở ra một thiết bị đầu cuối mới và thực hiện lệnh "echo hello" bên trong nó.


3
Điều này đã hoạt động nhưng tab mới đã được tạo trong một phiên bản riêng của Terminal. Vẫn còn đó tab mới trong phiên bản hiện tại của Terminal của tôi chứ?
Calvin Cheng

Nhân tiện, bạn có thể sử dụng do script ""với một chuỗi trống để tạo một thiết bị đầu cuối mới mà không cần đưa ra lệnh.
Chris Page

9

Nếu bạn sử dụng oh-my-zsh (mà mọi người sành sỏi nên sử dụng), sau khi kích hoạt plugin "osx" .zshrc, chỉ cần nhập tablệnh; nó sẽ mở một tab mới và cdtrong thư mục mà bạn đã ở trên.


Nó trông rất thú vị. Sự khác biệt giữa zcsh và bash thông thường là gì?
Calvin Cheng

Chúng rất giống nhau, nhưng thú vị nhất là nó có tính năng hoàn thành tab thông minh, mạnh mẽ và tự động sửa. Xem so sánh hay tại đây . Oh-my-zsh là thiết lập một môi trường với đẹp và tiện dụng thiết lập / plugins để giúp bạn bắt đầu
CharlesB

Xem nhanh liên kết so sánh của CharlesB. Rất thú vị. Nghe gần giống như vỏ BPython so với vỏ iPython.
Calvin Cheng

zsh quản lý để giữ xung quanh cruft cũ hơn để mất kiểm soát
James

bạn có thể cung cấp thêm thông tin về điều này? Lệnh tab là gì? Vào tabcó vẻ như không làm được gì
Solvitieg

7

Phím tắt cmd-tmở một tab mới, vì vậy bạn có thể chuyển tổ hợp phím này sang lệnh OSA như sau:

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


6

Tôi đã thêm những thứ này vào .bash_profile của mình để tôi có thể có quyền truy cập vào tabname và 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
}

Vì vậy, khi đang ở trên một tab cụ thể, bạn có thể chỉ cần nhập

tabname "New TabName"

để sắp xếp tất cả các tab đang mở mà bạn có. Nó tốt hơn nhiều so với việc lấy thông tin trên tab và thay đổi nó ở đó.


cảm ơn. bạn có biết cách giữ lại tên tab sau khi tôi thực hiện ssh từ tab và thoát khỏi phiên ssh không?
anjanb

4

Tôi biết đây là một bài viết cũ, nhưng điều này đã hiệu quả với tôi:

open -a Terminal "`pwd`"

Để chạy một lệnh như được yêu cầu bên dưới, hãy thực hiện một số jiggery:

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

Rất đẹp! Làm cách nào để làm nếu tôi muốn chuyển các lệnh sẽ chạy trong phiên bản mới của Terminal? : D
Strazan

@Strazan đã chỉnh sửa câu trả lời ở trên ... chúc các bạn vui vẻ !! Có vẻ như thiết bị đầu cuối sẽ nhận một tham số như vậy ...
neophytte

3

khi bạn đang ở trong cửa sổ dòng lệnh, lệnh + n => mở một dòng lệnh mới và lệnh + t => mở tab mới trong cửa sổ dòng lệnh hiện tại


1
điều này phải hoạt động từ dòng lệnh. về cơ bản là một tập lệnh. bởi vì đó là một nhiệm vụ lặp đi lặp lại
Gianfranco P.

2

Nếu bạn đang sử dụng iTerm , lệnh này sẽ mở một tab mới:

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

Nếu bạn cần thêm điều này vào .zshrc hoặc .bashrc, bạn có thể làm như vậy với một hàm thay vì bí danh (vì tất cả các thoát bạn sẽ phải làm). stackoverflow.com/a/20111135/1401336
Vigrant

@Andrew Schreiber: Nhưng điều khiển không chuyển sang tab mới. Ý tôi là nếu bạn có một số mã sau khi mở tab mới, mã đó sẽ được thực thi trong tab gốc. Có cách nào để cho script xử lý các lệnh sau trong tab mới không?
Ashwin

1
open -n -a Terminal

và bạn có thể chuyển thư mục đích làm tham số

open -n -a Terminal /Users

Điều này mở ra một cửa sổ mới cho tôi. Không phải là một tab.
stack-delay

0

Điều gì về đoạn mã đơn giản này, dựa trên một lệnh script chuẩn (echo):

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

0

Với X được cài đặt (ví dụ: từ homebrew hoặc Quartz), một "xterm &" đơn giản thực hiện (gần như) thủ thuật, nó sẽ mở ra một cửa sổ đầu cuối mới (không phải tab).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.