How to create a new tab in Terminal app without using SystemEvents

Hi. This is the last part of a very tedious script. I saved it for last because I’ve scoured the Internet and can’t find a solution. Here’s what I’m trying to do:

tell application "Terminal"
		activate
		if not (exists window 1) then
			reopen
		end if
		tell window 1 of application "Terminal"
			[b]create new tab[/b]
		end tell
		do script (ResultsFromSecondDialogText) in new tab of window 1
	end tell

Alternatively, I could create a new window. But I’m dealing with several potential scenarios:

  1. Terminal isn’t opened yet. Creating a new window creates two windows due to the default window that opens. This is compensated by the code above (if not exists window 1).
  2. Terminal is already opened and has a window set aside being used for a special purpose - like a half-done script saved aside.
  3. Terminal has a program running in Window 1 already and it won’t recognize the command passed to it by AppleScript.

Model: iMac 19,2
AppleScript: 2.7
Browser: Safari 537.36
Operating System: Other

Have you tried GUI scripting?

Something like this


if application "Terminal" is not running then tell application "Terminal" to activate
tell application "System Events"
	tell process "Terminal"
		set frontmost to true
		if not (exists window 1 of application "Terminal") then
			click menu item 1 of menu of menu item "New Window" of menu 1 of menu bar item "Shell" of menu bar 1
		end if
		click menu item 1 of menu of menu item "New Tab" of menu 1 of menu bar item "Shell" of menu bar 1
	end tell
end tell

Thanks for the response and script.

I’m trying to avoid making the user enable System Events to run the script.

If I can’t get round it, I’ll probably just have the script open in a second window. If there were a way to create a new window and then make it into a tab, that could work too. I’ll see what I can figure out.

[update]
An Apple employee told me that it’s a bug that the tabs didn’t work as expected and to submit a bug report. What I found is that the windows can’t be combined into a single window with multiple tabs. But if you manually create a new tab or manually name an existing tab, it becomes recognized as a tab.

I think the logic involves windows of tabs and windows with tabs with windows in them.

I’ve never spent any time scripting tabs but this is a confusing topic in Terminal. For example, I opened one terminal window and then opened two additional tabs (1 window with 3 visible tabs). I next ran the following script which returned a count of 3 windows and 1 tab. So, for scripting purposes, it appears that tabs almost seem not to exist in Terminal.

tell application "Terminal" -- one Terminal window with 3 tabs already open
	set windowCount to number of windows --> 3
	set tabCount to number of tabs of window 1 --> 1
	set rowCount to number of rows of window 2 --> 40
	-- set rowCount to number of rows of tab 2 of window 1 --> "error: Can’t get tab 2 of window 1"
end tell

I did find a way to create a new tab in Terminal in an AppleScript without using System Events. First, change the System Preference in the Dock pane to always prefer tabs when opening documents. Then, with a terminal window open, run the following script:

tell application "Terminal"
	do script ""
end tell

Clearly, changing a global system preference to get one script to work is not acceptable, but it does raise a question. Perhaps it would be best to avoid the issue of scripting windows/tabs in Terminal and let the user decide which they prefer in System Preferences.

As regards the three scenarios in Post 1, the following seems to meet all requirements under Catalina. I simulated a busy Terminal window with a “sleep 30” command. The do script line creates a new window or tab based on the System Preference setting noted above.

tell application "Terminal"
	if not running then
		activate
	else
		do script ""
	end if
end tell

I tried creating two windows, and then choosing the menu option Window>Merge All Windows. It puts both windows into tabs in a new window… or so it appears.

See the following script:

tell application "Terminal"
	set ListOfWindows to {}
	set ListOfWindows to the id of every window whose visible is true
end tell
ListOfWindows
--In my case, results were as follows: {3175, 3144}

So, I scripted the following add-on to my script above to test:

tell application "Terminal"
	repeat with a from 1 to length of ListOfWindows
		set frontmost of window id (item a of ListOfWindows) to true
		if name of window id (item a of ListOfWindows) is not (item a of ListOfWindows as text) then
			set custom title of window id (item a of ListOfWindows) to (item a of ListOfWindows as text)
		end if
		do script ("echo \"Window ID = \"" & (item a of ListOfWindows)) in window id (item a of ListOfWindows)
		beep
		delay 1
	end repeat
end tell

This cycles through the tabs in a slow visible way so I can confirm that the commands are all executing. What I noticed is that whatever “window” is frontmost is the selected tab. So, each tab behaves sort of like a window that is stuck to the tab bar. And whatever tab is selected, that tab’s name displays in the window’s title bar too.

That’s because each tab is a window. All the windows are there, and changing tabs just changes which one actually gets drawn on the screen.

Here is an oddity with “Terminal”

if one uses the “make new window” command, it fails but not completely.

tell application "Terminal"
	if not running then activate
	set WinList to windows
	display alert "Count of windows = " & (count WinList)
	try
		set nWin to make new window -- this will error out
	on error errorMessage number errorNumber from offendingObject
		display alert "ErrorNumber = " & errorNumber & return & "ErrorMessage = " & errorMessage
	end try
	-- even tho it errored out, a new invisible window was created
	set WinList to windows
	display alert "Count of windows = " & (count WinList)
	-- we can set it to be visible, but it is an empty window
	set visible of window 2 to true
end tell

one of the parameters of the “make” command is “with properties”.
If anyone could figure out if this needs to be passed with a particularly formed record, that would be awesome.


tell application "Terminal"
	activate
	try
		make new window
	end try
	tell last window to do script ""
end tell

delay 10 -- just to see visually for while

That doesn’t work.

If you count the number of windows before the line “tell last window to do script”
and then again after, you will see that the “make new window” command failed as usual
and the do script command created a third window.

tell application "Terminal"
	activate
	display alert (count windows) --ONE window
	try
		make new window
	end try
	display alert (count windows) --TWO windows
	tell last window to do script ""
	display alert (count windows) --THREE windows
	get windows
end tell

Still doesn’t work.

Are you testing any of these before you post?

The “make new tab” command doesn’t make a new tab

(not trying to sound like an ass)

yes you are right it doesn’t work. Funny problem.

After you create that window and make it visible, it does allow you to manipulate it a little.

set bounds of window 2 to {0, 200, 700, 800} 
set index of window 2 to 1

I wonder if you have to completely build the window from scratch - adding all of its internal elements and properties via command.

You might be onto something

remember is said that the make command uses a “with properties” optional paramater

I then tried this

tell application "Terminal"
	if not running then activate
	set WinList to windows
	display alert "Count of windows = " & (count WinList) -- the window is now bigger
	try
		set nWin to make new window with properties {bounds:{0, 200, 700, 800}} -- this will error out
	on error errorMessage number errorNumber from offendingObject
		display alert "ErrorNumber = " & errorNumber & return & "ErrorMessage = " & errorMessage
	end try
	-- even tho it errored out, a new invisible window was created
	set wid to id of window 2 -- get the id so I dont have to worry about the index changing
	-- we can set it to be visible, but it is an empty window
	set visible of window id wid to true
end tell

Now to figure out all the things it needs to be a fully functional terminal window

I think it makes no sense to continue looking for a solution to this problem. And that’s because Peavine has already shown the right solution.

From myself, I want to add only that the new tab is completely controllable, which is what the OP wants. It is enough to create a reference (newTab, for example) to the new tab, and then set its properties as you want:

-- NOTE:
-- First, change the System Preference in the Dock pane
-- to "Always prefer tabs when opening documents".

tell application "Terminal"
	activate
	if not (exists window 1) then reopen
	tell window 1 to set newTab to do script ""
	tell newTab
		set selected to true
		set custom title to "I am one new terminal Tab"
	end tell
	return newTab
end tell