153

Is it possible to open a new tab in Mac OS X's terminal from the command line in a currently opened tab?

I know that the keyboard shortcut to open a new tab in Terminal is "CMD+t" but I am looking for a script-based solution executed in the command line.

mklement0
  • 382,024
  • 64
  • 607
  • 775
Calvin Cheng
  • 35,640
  • 39
  • 116
  • 167

15 Answers15

175

Update: This answer gained popularity based on the shell function posted below, which still works as of OSX 10.10 (with the exception of the -g option).
However, a more fully featured, more robust, tested script version is now available at the npm registry as CLI ttab, which also supports iTerm2:

  • If you have Node.js installed, simply run:

    npm install -g ttab
    

    (depending on how you installed Node.js, you may have to prepend sudo).

  • Otherwise, follow these instructions.

  • Once installed, run ttab -h for concise usage information, or man ttab to view the manual.


Building on the accepted answer, below is a bash convenience function for opening a new tab in the current Terminal window and optionally executing a command (as a bonus, there's a variant function for creating a new window instead).

If a command is specified, its first token will be used as the new tab's title.

Sample invocations:

    # 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: When you run newtab (or newwin) from a script, the script's initial working folder will be the working folder in the new tab/window, even if you change the working folder inside the script before invoking newtab/newwin - pass eval with a cd command as a workaround (see example above).

Source code (paste into your bash profile, for instance):

# 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
  • 382,024
  • 64
  • 607
  • 775
  • 3
    @jcollum My pleasure; glad you find it useful. I just updated the post with a caveat re working folders and also updated the code: added options `-g` (don't activate Terminal when creating the new tab/window) and `-G` (don't activate Terminal *and* don't change the active tab inside Terminal) - helpful, for instance, when starting a server in the background. Note that when creating a new tab this way, Terminal still has to be activated briefly before the previously active application is reactivated. – mklement0 Dec 13 '12 at 03:39
  • @mklement0 the new tab has the Home working directory, no matter what. I'm finding very difficult to change working directory of the new tab from within a script. Am I missing something? – Leonardo Jun 30 '13 at 01:14
  • 1
    @Leonardo The new tab has the same working directory as the tab from which the function was invoked. Changing to a different folder inside a script before calling `newtab`, unfortunately, does NOT work. The workaround is to pass an `eval` statement with a `cd` command to `newtab`; e.g.: `newtab eval "cd ~/Library/Application\ Support; ls"`. Double-quote the entire command passed to `eval`, and use backslash-escaping inside. – mklement0 Jun 30 '13 at 06:30
  • I'm getting an error with this script in my bash profile when running source ~/.bash_profile "-bash: /Users/username/.bash_profile: line 23: syntax error near unexpected token `(' -bash: /Users/username/.bash_profile: line 23: `newtab() {'" – BrightIntelDusk Mar 17 '15 at 17:44
  • I had a conflicting alias with newtab which I had to delete. Though adding function in front of newtab eliminated the name conflict error. – BrightIntelDusk Mar 17 '15 at 17:48
  • 1
    @IntegrityFirst: Per your suggestion I've switched the functions signatures to `function newtab` and `function newwin` (however, NO parentheses), so that should avoid the collision with aliases when _defining_ the functions, but note that on _invocation_ an alias of the same name takes precedence (to bypass the alias, ad-hoc, quote any part of the function name, e.g.: `\newtab`). – mklement0 Mar 17 '15 at 19:19
  • 2
    @IntegrityFirst: Here's what I learned: Using POSIX `() { ... }` function syntax makes `` subject to _alias expansion_, which breaks the function definition (parsing error!) if an alias `` happens to be defined. Not typically a concern, since in normally invoked scripts alias expansion is turned OFF by default. However, in scripts SOURCED from an INTERACTIVE shell - such as in profile / initialization files - alias expansion IS turned on. Fix: Use non-POSIX `function { ... }` syntax to define the function - `` is then NOT subject to alias expansion. – mklement0 Mar 17 '15 at 19:35
  • 1
    Thanks! this adds an ``if [ "${BASH_SOURCE}" == "${0}" ]`` with a case statement so it can be called as a script (e.g. ``newtab.sh``, ``newwin.sh``): https://gist.github.com/westurner/01b6be85e5a51fda22a6 – Wes Turner May 27 '15 at 17:36
  • 1
    @WesTurner: Thanks, that's helpful; I actually just published a script as well via the npm registry; see the top of the updated answer. – mklement0 Jun 01 '15 at 06:13
  • I know this post is old, but the code still works. However, if I try to run an install command with this or source a .sh file (tested with a homebrew install) it works, but the output of the command is in the original window, not the new tab or new window, even when using the `-g` flag. Using macOS 10.14 and 11.6 here. If anyone has info to keep all output in new window until it closes, would appreciate it. – liquidRock Nov 17 '21 at 15:58
147

Try this:

osascript -e 'tell application "Terminal" to activate' \
  -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
  -e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'

But if you need to run dynamic command, set myCommand variable, and replace last line with:

-e "tell application \"Terminal\" to do script \"${myCommand};\" in selected tab of the front window";
Top-Master
  • 7,611
  • 5
  • 39
  • 71
Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • D'Oh! I missed your comment completely, found a similar solution via google. One difference: it didn't work for me (on 10.6.8) unless Terminal was the frontmost application, so I added the "activate" to force it to the front. – Gordon Davisson Aug 25 '11 at 17:53
  • 6
    edit: How do I put a new command e.x `echo hello` into this new tab. – ThomasReggi Aug 26 '12 at 17:45
  • 25
    @ThomasReggi: Add `-e 'tell application "Terminal" to do script "echo hello" in selected tab of the front window'` to the end of the osascript command. – Gordon Davisson Aug 26 '12 at 20:14
  • @GordonDavisson: It is only valid in "Terminal", but not in "iTerm" – clevertension Oct 10 '14 at 13:54
  • 2
    @clevertension for iTerm it is just `open -a iTerm ~/Applications/ ` – onmyway133 May 15 '16 at 21:12
  • @GordonDavisson How would run a script in tab 1 before open tab 2 and then run the second script in tab 2? – angry kiwi Jul 03 '16 at 11:45
  • and then how do I CD to specific path ? – Ciasto piekarz Dec 23 '18 at 02:17
  • 1
    @Ciastopiekarz Do you mean in the newly opened tab? Use the same approach as my answer to ThomasReggi: add `-e 'tell application "Terminal" to do script "cd /path/to/target/directory" in selected tab of the front window'`. Note that if the path is coming from a variable, you'll need to use a double-quoted string instead of single-quoted, and escape the inner quoted string, *and* probably the path itself. – Gordon Davisson Dec 23 '18 at 06:02
  • @GordonDavisson , I will give it a try, however I installed `ttab` and it works great. – Ciasto piekarz Dec 23 '18 at 06:04
25
osascript -e 'tell app "Terminal"
   do script "echo hello"
end tell'

This opens a new terminal and executes the command "echo hello" inside it.

Szymon Morawski
  • 765
  • 7
  • 12
  • 7
    This worked but the new tab was created in a separate instance of Terminal. Is there anyway the new tab remains in the current instance of my Terminal? – Calvin Cheng Aug 24 '11 at 07:35
  • 1
    By the way, you can use `do script ""` with an empty string to create a new terminal without issuing a command. – Chris Page Aug 25 '11 at 10:47
20

Here's how it's done by 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
}

After adding this to your .bash_profile, you'd use the tab command to open the current working directory in a new tab.

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

dleavitt
  • 1,386
  • 13
  • 14
  • 1
    Very helpful. Using this in my .bash_profile, I'm able to launch a bunch of tabs and ssh to them automatically. Of course, I've ssh key-pair authentication enabled – Sandeep Kanabar Jul 30 '16 at 06:50
18

If you use oh-my-zsh (which every trendy geek should use), after activating the macos plugin in .zshrc, simply enter the tab command; it will open a new tab and cd in the directory your were on.

CharlesB
  • 86,532
  • 28
  • 194
  • 218
  • It looks very interesting. What's the difference between zcsh and conventional bash? – Calvin Cheng Aug 24 '11 at 08:31
  • They are very similar, but most interestingly it has intelligent, powerful tab completion and auto-correction. See good comparison [here](http://friedcpu.wordpress.com/2007/07/24/zsh-the-last-shell-youll-ever-need/). Oh-my-zsh is setting an environment with nice and handy settings/plugins to get you started – CharlesB Aug 24 '11 at 08:43
  • Took a quick look at CharlesB's comparison link. Very interesting. Sounds almost like BPython shell versus iPython shell. – Calvin Cheng Aug 25 '11 at 10:01
  • zsh manages to keep around even more old cruft to lose control off – Tegra Detra Apr 05 '14 at 14:27
  • 1
    Can you provide more information on this? What is the tab command? Entering `tab` doesn't appear to do anything – png Jul 22 '20 at 00:30
  • 1
    @Solvitieg it’s 9 years old it might be obsolete now – CharlesB Jul 22 '20 at 13:42
  • 4
    @Solvitieg @CharlesB Not obsolete. Just enabled and used it. Be sure to enable the `osx` plugin in your .zshrc file. – Chase Giunta Oct 01 '20 at 17:19
  • 2
    `osx` has been moved to `macos` -- https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/macos – keithpjolley Mar 18 '22 at 12:11
8

I added these to my .bash_profile so I can have access to tabname and 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
}

So when you're on a particular tab you can just type

tabname "New TabName"

to organize all the open tabs you have. It's much better than getting info on the tab and changing it there.

richtera
  • 91
  • 1
  • 3
  • thanks. do you know how to retain the tab name after I do a ssh from the tab and exit from the ssh session ? – anjanb Sep 05 '14 at 06:19
8

I know this is an old post, but this worked for me:

open -a Terminal "`pwd`"

To run a command as requested below takes some jiggery:

echo /sbin/ping 8.8.8.8 > /tmp/tmp.sh;chmod a+x /tmp/tmp.sh;open -a Terminal /tmp/tmp.sh
neophytte
  • 648
  • 2
  • 11
  • 25
  • Very nice! How do I do if I wanna pass commands that will run in the new instance of Terminal? :D – Strazan Jan 29 '20 at 13:52
  • @Strazan edited answer above ... have fun!! Looks like terminal will take a parameter like that ... – neophytte Feb 10 '20 at 01:10
  • 1
    When I tried this, it opened a new terminal window rather than open a new tab on an existing one – wytten Feb 19 '21 at 14:41
  • What OS & Terminal are you running? Worked for me today on Darwin Kernel Version 20.3.0 & Terminal Version 2.11 (440) – neophytte Feb 21 '21 at 00:38
  • running this from a script didn't let the terminal be controlled by user (was expecting stdin or whatever) – Nir O. Jan 09 '23 at 08:13
6

The keyboard shortcut cmd-t opens a new tab, so you can pass this keystroke to OSA command as follows:

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

Aziz Alto
  • 19,057
  • 5
  • 77
  • 60
3
open -n -a Terminal

and you can pass the target directory as parameter

open -n -a Terminal /Users
Everton Santos
  • 472
  • 1
  • 4
  • 8
2

when you are in a terminal window, command + n => opens a new terminal and command + t => opens a new tab in current terminal window

xdev
  • 659
  • 11
  • 23
1

If you are using iTerm this command will open a new tab:

osascript -e 'tell application "iTerm" to activate' -e 'tell application "System Events" to tell process "iTerm" to keystroke "t" using command down'
Andrew Schreiber
  • 14,344
  • 6
  • 46
  • 53
  • If you need to add this to a .zshrc or a .bashrc you can do so with a function instead of an alias (because of all the escaping you will end up having to do). https://stackoverflow.com/a/20111135/1401336 – Vigrant Aug 21 '18 at 19:56
  • @Andrew Schreiber : But the control does not transfer to the new tab. I mean if you have some code after opening the new tab, that code gets executed in the original tab. Is there a way to tell the script to process the following commands in the new tab? – Ashwin Aug 10 '19 at 08:07
0

What about this simple snippet, based on a standard script command (echo):

# set mac osx's terminal title to "My Title"
echo -n -e "\033]0;My Title\007"
Adrien Joly
  • 5,056
  • 4
  • 28
  • 43
0

With X installed (e.g. from homebrew, or Quartz), a simple "xterm &" does (nearly) the trick, it opens a new terminal window (not a tab, though).

0

I made a simplified version that works around the AppleScript bug that generates a new UI.

on run argv
    set scpt to first item in argv
    set flag to application "Terminal" is not running
    tell application "Terminal"
        do script scpt
        activate
        delay 1.0E-5
        if flag then close back window
    end tell
end run

Or this also works

open -a Terminal.app path/file.sh
jredfox_
  • 19
  • 6
0

Another option is to use make to organize your terminal tab launching a little better. For example, you could create a make file that looks like this:

Makefile

.PHONY:launchtabgroup1
launchtabgroup1:
    chmod u+r+x scripts/launch_tabgroup1.sh
    scripts/launch_tabgroup1.sh

.PHONY:launchtabgroup2
launchtabgroup2:
    chmod u+r+x scripts/launch_tabgroup2.sh
    scripts/launch_tabgroup2.sh

Then within a subdirectory of where you store your make file, create a scripts directory that has all the commands to open whatever tabs you want for that group. Like this:

launch_tabgroup1.sh

#!/usr/bin/env sh


osascript -e 'tell application "Terminal" to activate' \
  -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
  -e 'tell application "Terminal" to do script "cd ../path/to/desired/directory" in selected tab of the front window'

osascript -e 'tell application "Terminal" to activate' \
  -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
  -e 'tell application "Terminal" to do script "cd ../path/to/desired/directory" in selected tab of the front window'

osascript -e 'tell application "Terminal" to activate' \
  -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
  -e 'tell application "Terminal" to do script "cd ../path/to/desired/directory" in selected tab of the front window'

You would make corresponding entries in the Makefile that call the respective .sh files, which spin up the tabs in the group!

To actually spin up the tab groups navigate to the Makefile directory and run make launchtabgroup1 or make launchtabgroup2.