Öffnen Sie die neue Registerkarte "Terminal" über die Befehlszeile (Mac OS X).

116

Ist es möglich, eine neue Registerkarte im Mac OS X-Terminal über die Befehlszeile in einer aktuell geöffneten Registerkarte zu öffnen?

Ich weiß, dass die Tastenkombination zum Öffnen einer neuen Registerkarte in Terminal "CMD + t" lautet, suche jedoch nach einer skriptbasierten Lösung, die in der Befehlszeile ausgeführt wird.

Calvin Cheng
quelle

Antworten:

126

Versuche dies:

osascript -e 'tell application "Terminal" to activate' -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down'
Gordon Davisson
quelle
D'Oh! Ich habe Ihren Kommentar komplett verpasst und über Google eine ähnliche Lösung gefunden. Ein Unterschied: Es hat bei mir nicht funktioniert (am 10.6.8), es sei denn, Terminal war die vorderste Anwendung, also habe ich das "Aktivieren" hinzugefügt, um es nach vorne zu zwingen.
Gordon Davisson
5
Bearbeiten: Wie füge ich einen neuen Befehl ex echo helloin diese neue Registerkarte ein?
Thomas Reggi
22
@ThomasReggi: Am -e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'Ende des Befehls osascript hinzufügen.
Gordon Davisson
2
@clevertension für iTerm ist es nuropen -a iTerm ~/Applications/
onmyway133
1
@Ciastopiekarz Meinst du in der neu geöffneten Registerkarte? Verwenden Sie den gleichen Ansatz wie meine Antwort auf Thomas Reggi: Hinzufügen -e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'. Beachten Sie, dass Sie, wenn der Pfad von einer Variablen stammt, eine Zeichenfolge in doppelten Anführungszeichen anstelle von einfachen Anführungszeichen verwenden und die Zeichenfolge in inneren Anführungszeichen und wahrscheinlich den Pfad selbst maskieren müssen.
Gordon Davisson
163

Update : Diese Antwort wurde aufgrund der unten angegebenen Shell-Funktion immer beliebter, die ab OSX 10.10 (mit Ausnahme der -gOption) weiterhin funktioniert .
Allerdings ist eine vollständiger Funktionsumfang, robuste, getestet Skriptversion ist jetzt an der zur Verfügung npm Registrierung als CLIttab , die auch unterstützt iTerm2 :

  • Wenn Sie Node.js installiert haben, führen Sie einfach Folgendes aus:

    npm install -g ttab
    

    (Je nachdem, wie Sie Node.js installiert haben, müssen Sie möglicherweise ein Präfix vorstellen. sudo)

  • Befolgen Sie andernfalls diese Anweisungen .

  • Führen Sie ttab -hnach der Installation kurze Nutzungsinformationen aus oder man ttablesen Sie das Handbuch.


Aufbauend auf der akzeptierten Antwort finden Sie unten eine Bash- Convenience-Funktion zum Öffnen einer neuen Registerkarte im aktuellen Terminalfenster und zum optionalen Ausführen eines Befehls (als Bonus gibt es stattdessen eine Variantenfunktion zum Erstellen eines neuen Fensters ).

Wenn ein Befehl angegeben wird, wird sein erstes Token als Titel der neuen Registerkarte verwendet.

Beispielaufrufe:

    # 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 : Wenn Sie ein Skript ausführen newtab(oder ausführen newwin), ist der ursprüngliche Arbeitsordner des Skripts der Arbeitsordner in der neuen Registerkarte / im neuen Fenster, auch wenn Sie den Arbeitsordner im Skript ändern, bevor Sienewtab / newwin- pass evalmit einem cdBefehl als Problemumgehung aufrufen (siehe Beispiel oben).

Quellcode (zum Beispiel in Ihr Bash-Profil einfügen):

# 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
quelle
3
@jcollum Es ist mir ein Vergnügen; Ich bin froh, dass du es nützlich findest. Ich habe gerade den Beitrag mit einer Einschränkung aktualisiert, die Ordner überarbeitet, und auch den Code aktualisiert: Optionen hinzugefügt -g(Terminal beim Erstellen der neuen Registerkarte / des neuen Fensters -Gnicht aktivieren ) und (Terminal nicht aktivieren und die aktive Registerkarte im Terminal nicht ändern ) - hilfreich zum Beispiel beim Starten eines Servers im Hintergrund. Beachten Sie, dass beim Erstellen einer neuen Registerkarte auf diese Weise das Terminal noch kurz aktiviert werden muss, bevor die zuvor aktive Anwendung wieder aktiviert wird.
mklement0
1
@Leonardo Die neue Registerkarte hat dasselbe Arbeitsverzeichnis wie die Registerkarte, von der aus die Funktion aufgerufen wurde. Das Wechseln in einen anderen Ordner innerhalb eines Skripts vor dem Aufruf newtabfunktioniert leider NICHT. Die Problemumgehung besteht darin, eine evalAnweisung mit einem cdBefehl an zu übergeben newtab. zB : newtab eval "cd ~/Library/Application\ Support; ls". Zitieren Sie den gesamten an übergebenen Befehl in doppelte Anführungszeichen evalund verwenden Sie Backslash-Escape im Inneren.
mklement0
1
@IntegrityFirst: Gemäß Ihrem Vorschlag habe ich die Funktionssignaturen auf function newtabund function newwin(jedoch KEINE Klammern) umgestellt , damit die Kollision mit Aliasen beim Definieren der Funktionen vermieden wird. Beachten Sie jedoch, dass beim Aufruf ein gleichnamiger Alias ​​Vorrang hat (bis Umgehen Sie den Alias ​​ad-hoc und zitieren Sie einen beliebigen Teil des Funktionsnamens, z \newtab. B. :) .
mklement0
2
@IntegrityFirst: Folgendes habe ich gelernt: Die Verwendung der POSIX- <name>() { ... }Funktionssyntax macht<name> unter Alias - Erweiterung , die die Definition der Funktion unterbricht , wenn ein Alias (Parsing - Fehler!) <name>Definiert werden , geschieht. Dies ist normalerweise kein Problem, da in normalerweise aufgerufenen Skripten die Aliaserweiterung standardmäßig deaktiviert ist. In Skripten, die aus einer INTERACTIVE-Shell stammen, z. B. in Profil- / Initialisierungsdateien, ist die Alias-Erweiterung jedoch aktiviert. Fix: Verwenden Sie eine Nicht-POSIX- function <name> { ... } Syntax, um die Funktion zu definieren - <name>unterliegt dann NICHT der Alias-Erweiterung.
mklement0
1
Vielen Dank! dies fügt eine hinzuif [ "${BASH_SOURCE}" == "${0}" ] mit einem Case - Anweisung , so kann es als ein Skript (zB genannt werden newtab.sh, newwin.sh): gist.github.com/westurner/01b6be85e5a51fda22a6
Wes Turner
18

So geht's mit 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
}

Nachdem Sie dies zu Ihrem .bash_profile hinzugefügt haben, öffnen Sie mit dem tabBefehl das aktuelle Arbeitsverzeichnis auf einer neuen Registerkarte.

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

Dleavitt
quelle
1
Sehr hilfreich. Wenn ich dies in meinem .bash_profile verwende, kann ich eine Reihe von Registerkarten und SSH automatisch starten. Natürlich habe ich die SSH-Schlüsselpaar-Authentifizierung aktiviert
Sandeep Kanabar
16
osascript -e 'tell app "Terminal"
   do script "echo hello"
end tell'

Dies öffnet ein neues Terminal und führt den darin enthaltenen Befehl "echo hello" aus.

Szymon Morawski
quelle
3
Dies funktionierte, aber die neue Registerkarte wurde in einer separaten Instanz von Terminal erstellt. Gibt es trotzdem die neue Registerkarte in der aktuellen Instanz meines Terminals?
Calvin Cheng
Übrigens können Sie do script ""mit einer leeren Zeichenfolge ein neues Terminal erstellen, ohne einen Befehl auszugeben.
Chris Page
9

Wenn Sie oh-my-zsh verwenden (das jeder trendige Geek verwenden sollte), geben Sie nach Aktivierung des Plugins "osx" .zshrceinfach den tabBefehl ein. Es öffnet sich eine neue Registerkarte und cdin dem Verzeichnis, in dem Sie sich befanden.

CharlesB
quelle
Es sieht sehr interessant aus. Was ist der Unterschied zwischen zcsh und konventioneller Bash?
Calvin Cheng
Sie sind sich sehr ähnlich, aber am interessantesten ist, dass sie intelligente, leistungsstarke Registerkarten vervollständigen und automatisch korrigieren. Siehe guten Vergleich hier . Oh-my-zsh stellt eine Umgebung mit netten und praktischen Einstellungen / Plugins ein, um Ihnen den
Einstieg zu erleichtern
Wirf einen kurzen Blick auf den Vergleichslink von CharlesB. Sehr interessant. Klingt fast wie eine BPython-Shell im Vergleich zu einer iPython-Shell.
Calvin Cheng
zsh schafft es, noch mehr alte Cruft zu halten, um die Kontrolle zu verlieren
James
Können Sie hierzu weitere Informationen geben? Was ist der Tabulatorbefehl? Die Eingabe tabscheint nichts zu
bewirken
7

Die Tastenkombination cmd-töffnet eine neue Registerkarte, sodass Sie diesen Tastendruck wie folgt an den OSA-Befehl übergeben können:

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

Aziz Alto
quelle
6

Ich habe diese zu meinem .bash_profile hinzugefügt, damit ich auf tabname und newtab zugreifen kann

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
}

Wenn Sie sich also auf einer bestimmten Registerkarte befinden, können Sie einfach eingeben

tabname "New TabName"

um alle geöffneten Registerkarten zu organisieren. Es ist viel besser, als Informationen auf der Registerkarte abzurufen und dort zu ändern.

richtera
quelle
Vielen Dank. Wissen Sie, wie Sie den Tab-Namen beibehalten, nachdem ich ein SSH von der Registerkarte aus ausgeführt und die SSH-Sitzung beendet habe?
Anjanb
4

Ich weiß, dass dies ein alter Beitrag ist, aber das hat bei mir funktioniert:

open -a Terminal "`pwd`"

Um einen Befehl wie unten angefordert auszuführen, müssen Sie einige Schritte ausführen:

echo /sbin/ping 8.8.8.8 > /tmp/tmp.sh;chmod a+x /tmp/tmp.sh;open -a Terminal /tmp/tmp.sh
Neuling
quelle
Sehr schön! Wie gehe ich vor, wenn ich Befehle übergeben möchte, die in der neuen Instanz von Terminal ausgeführt werden? : D
Strazan
@ Trazan bearbeitete Antwort oben ... viel Spaß !! Es sieht so aus, als würde das Terminal einen
solchen
3

Wenn Sie sich in einem Terminalfenster befinden, öffnet Befehl + n => ein neues Terminal und Befehl + t => öffnet eine neue Registerkarte im aktuellen Terminalfenster

xdev
quelle
1
Dies muss über die Befehlszeile funktionieren. im Grunde ein Skript. weil es eine sich wiederholende Aufgabe ist
Gianfranco P.
2

Wenn Sie iTerm verwenden, öffnet dieser Befehl eine neue Registerkarte:

osascript -e 'tell application "iTerm" to activate' -e 'tell application "System Events" to tell process "iTerm" to keystroke "t" using command down'
Andrew Schreiber
quelle
Wenn Sie dies zu einem .zshrc oder einem .bashrc hinzufügen müssen, können Sie dies mit einer Funktion anstelle eines Alias ​​tun (wegen all der Flucht, die Sie am Ende machen müssen). stackoverflow.com/a/20111135/1401336
Vigrant
@ Andrew Schreiber: Das Steuerelement wird jedoch nicht auf die neue Registerkarte übertragen. Ich meine, wenn Sie nach dem Öffnen der neuen Registerkarte Code haben, wird dieser Code auf der ursprünglichen Registerkarte ausgeführt. Gibt es eine Möglichkeit, das Skript anzuweisen, die folgenden Befehle auf der neuen Registerkarte zu verarbeiten?
Ashwin
1
open -n -a Terminal

und Sie können das Zielverzeichnis als Parameter übergeben

open -n -a Terminal /Users
Everton Santos
quelle
Dies öffnet mir ein neues Fenster. Kein Tab.
Stapelverzögerung
0

Was ist mit diesem einfachen Snippet, das auf einem Standard-Skriptbefehl (Echo) basiert:

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

Wenn X installiert ist (z. B. von Homebrew oder Quartz), reicht ein einfaches "xterm &" (fast) aus, um ein neues Terminalfenster zu öffnen (allerdings keine Registerkarte).

Immanuel Kant
quelle