从命令行打开新的终端选项卡(Mac OS X)


116

是否可以从命令行中当前打开的选项卡中的Mac OS X终端中打开新选项卡?

我知道在终端中打开新选项卡的键盘快捷键是“ CMD + t”,但是我正在寻找在命令行中执行的基于脚本的解决方案。

Answers:


126

试试这个:

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

噢!我完全想念您的评论,并通过Google找到了类似的解决方案。区别之一:对我来说(在10.6.8上)不起作用,除非Terminal是最前面的应用程序,所以我添加了“ activate”将其强制显示在最前面。
戈登·戴维森

5
编辑:如何将新命令ex echo hello放入此新选项卡。
ThomasReggi 2012年

22
@ThomasReggi:添加-e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'到osascript命令的末尾。
Gordon Davisson

2
@clevertension for iTerm它只是open -a iTerm ~/Applications/
onmyway133 '16

1
@Ciastopiekarz您的意思是在新打开的选项卡中吗?使用与我对ThomasReggi的回答相同的方法:add -e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'。请注意,如果路径来自变量,则需要使用双引号而不是单引号,并转义内部带引号的字符串以及路径本身。
戈登·戴维森

163

更新:根据以下发布的Shell函数,此答案开始流行,该函数自OSX 10.10起仍然有效(该-g选件除外)。
然而,功能更全面,更稳健,测试脚本版本现在可在故宫注册表的CLIttab,这也支持iTerm2

  • 如果安装了Node.js,只需运行:

    npm install -g ttab
    

    (取决于安装Node.js的方式,您可能需要添加sudo)。

  • 否则,请遵循以下说明

  • 安装后,请运行ttab -h以获取简明的用法信息或man ttab查看手册。


在接受的答案的基础上,下面是一个bash 便利功能,用于在当前“终端”窗口中打开一个新选项卡并可选地执行命令(此外,还有一个变体函数用于创建新窗口)。

如果指定了命令,则其第一个标记将用作新选项卡的标题。

样本调用:

    # 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 newtabfunction newwin(但是,没有括号),因此在定义函数时应避免与别名冲突,但是请注意,在调用时,具有相同名称的别名优先(绕开别名ad-hoc,在函数名称的任何部分加上引号,例如:)\newtab
mklement0 2015年

2
@IntegrityFirst:这是我所学到的:使用POSIX <name>() { ... }函数语法使得<name>别名扩展,它打破了函数的定义,如果一个别名(解析错误!)<name>恰好被定义。通常无需担心,因为在通常调用的脚本中,别名扩展默认情况下处于关闭状态。但是,在从INTERACTIVE Shell中采购的脚本中(例如,在配置文件/初始化文件中),别名扩展已打开。修复:使用非POSIX function <name> { ... } 语法定义函数- <name>然后不受别名扩展的限制。
mklement0 2015年

1
谢谢!这将增加if [ "${BASH_SOURCE}" == "${0}" ]一个case语句,因此它可以被称为一个脚本(例如newtab.shnewwin.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

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的比较链接。很有意思。听起来几乎像BPython shell与iPython shell。
加尔文·郑

zsh设法保留了更多的旧文件以失去控制权
James

您可以提供更多信息吗?tab命令是什么?输入tab似乎无计可施
Solvitieg

7

键盘快捷键cmd-t将打开一个新选项卡,因此您可以按如下所示将此击键传递给OSA命令:

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


6

我将它们添加到我的.bash_profile中,因此我可以访问tabname和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 2014年

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

@Strazan编辑的答案上面...玩得开心!!看起来终端将采用这样的参数...
neophytte

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 '18

@Andrew Schreiber:但是控件不会转移到新选项卡。我的意思是,如果在打开新选项卡后有一些代码,那么该代码将在原始选项卡中执行。有没有办法告诉脚本在新选项卡中处理以下命令?
阿什温


0

基于标准脚本命令(echo)的这个简单代码片段呢?

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

0

安装了X(例如从自制软件或Quartz)后,一个简单的“ xterm&”(几乎)就完成了窍门,它打开了一个新的终端窗口(不过不是选项卡)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.