2

I have a zsh script where I prompt for user input every 15 minutes. How can I make the tab of Terminal that the script is running in open up / focus? open -a Terminal just opens the whole window.

I'm aware of this trick to get current application and re-open it, is there a way to extend it to tabs/sessions?

term=$(/usr/bin/osascript -e "copy path to frontmost application as text to stdout")
/usr/bin/osascript -e 'tell application $term to activate'

Also aware of this trick to go back to an old tab, although (1) I couldn't get it to work and (2) I need the data in stdout so zsh can use it.

osascript \
    -e 'tell application "Terminal" to set oldTab to the selected tab of the front window' \
    -e 'tell application "System Events" to tell process "Terminal" to keystroke "t" using command down' \
    -e 'delay 1' \
    -e 'tell application "Terminal" to set selected of oldTab to true'
5
  • Could you please clarify what it is you are trying to do? Are you trying to have the shell script itself refocus the tab/window in which the shell script is running? In other word, do you want to start the shell script and when the 15 minutes are up, regardless of what app is frontmost, you want Terminal to come frontmost to the tab/window in which the shell script is running and this all be done programmatically? May 30 '21 at 1:54
  • Yes, precisely. Well put.
    – Luke Miles
    May 30 '21 at 1:55
  • Big sur (11.4).
    – Luke Miles
    May 30 '21 at 1:57
  • Can you share the shell script or at least lay it out a bit and how you have the timer set/running in the shell script? May 30 '21 at 1:59
  • Yeah right now it's just a sleep 900. So I do some processing and tasks, display some data, get input with read...
    – Luke Miles
    May 30 '21 at 3:19
1
+50

Based on your reply of "Yes, precisely. Well put." to my comment under the OP...

Could you please clarify what it is you are trying to do? Are you trying to have the shell script itself refocus the tab/window in which the shell script is running? In other word, do you want to start the shell script and when the 15 minutes are up, regardless of what app is frontmost, you want Terminal to come frontmost to the tab/window in which the shell script is running and this all be done programmatically?

The following example AppleScript code used in conjunction with osascript in a zsh shell script should do as wanted. Obviously the value of the sleep command is just for testing purposes, use whatever it is you are now using as the timer within your current zsh shell script.

#!/bin/zsh

    # First line of code of shell script.

winID="$(osascript -e 'id of window 1 of app "Terminal"')"

    # Function to refocus window of running script.

refocusWindow() {

        # Code to refocus window of the
        # running shell script using the 
        # window id retrieved from the first 
        # line of code in the shell script.

    osascript <<EOS
    tell app "Terminal"
        set frontmost of windows whose id = $winID to true
        activate
    end tell
EOS
}

# Do some stuff...
# Your other code goes here.

sleep 5

refocusWindow

Notes:

In Terminal, it does not matter how may tabs/windows there are as there is only one tab per window, even if the window appears to have multiple tabs. In other words, asking Terminal to count windows and count tabs of windows will return the same number. Thus there it no need to loop thru tabs to achieve the goal herein, just windows, and actually in this case there really is no need to loop thru windows.

Note that macOS Sierra what the last version in which Terminal supported multiple tabs of a window programmatically. In other words, from the UI a single window with two tabs there would be tab 1 of window 1 and tab 2 of window 1, but since macOS High Sierra from the UI a single window with two tabs there would be tab 1 of window 1 and tab 1 of window 2, and thus no longer the need to loop thru tabs.

There is all so no need to do something like set selected of tab j of window i to true as once a given window is set frontmost, the value of tab 1 of window i is already set to true as a result.

The example shell script and AppleScript code, shown above, was tested in Terminal as an executable shell script under macOS Catalina and macOS Big Sur with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.

  • 1 Assumes necessary and appropriate setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

As we do not know how you have your zsh shell script coded, you'll have to work in the code presented herein to suite your needs.

1
  • @Luke Miles, I've reworked the AppleScript code to more directly set the target window running the shell script to be frontmost. There was really no need to loop anything. Thanks! May 30 '21 at 4:50
1

This is a little awkward since I can't run this code from within your script (nor within an applescript) but this osascript should allow you to specify a desired tab (tp) and switch to it from any other within the same window.

osascript -e '
tell application "Terminal" to set tp to item 1 of (tabs of window 1 whose selected is true)
tell application "System Events" to tell process "Terminal" to keystroke "t" using command down
delay 1
tell application "Terminal" to set selected of tp to true'

I think your issue was just a syntax one: e.g. selected tab versus tab whose selected is true.

Each line does the following:

  • Sets variable tp to the active tab
  • Creates a new tab using system events (which becomes the active tab)
  • Delay 1
  • Makes tp the active tab

The variable tp will resemble this:

--> tab 3 of window id 360 of application "Terminal"

Note, there are some alternatives to setting tp to the active tab but they're more complex.

11
  • Hmm this seems to do nothing for me?
    – Luke Miles
    May 29 '21 at 18:45
  • @Luke Miles, RE: "Hmm this seems to do nothing for me?" -- the original code posted in this answer had a trailing space after each `\` and is what caused it to fail. May 29 '21 at 19:33
  • 1
    @user3439894 Thanks. My intent was for visual formatting so that it the four elements could be seen (rather than ease of copy/paste). It is easy enough to strip out the line endings (I hope).
    – Mockman
    May 29 '21 at 22:14
  • 1
    What about this, on its own? 'tell application "Terminal" to set selected of item 1 of (tabs of window 1) to true'
    – Mockman
    May 30 '21 at 1:22
  • 1
    This paradigm set selected of tab x of window y to true has not been valid since macOS High Sierra, as Terminal in macOS Sierra was the last to programmatically support tab x of window y. In other words, from the UI a single window with two tabs there would be tab 1 of window 1 and tab 2 of window 1, but since macOS High Sierra from the UI a single window with two tabs there would be tab 1 of window 1 and tab 1 of window 2. While it was not known what version of macOS the OP was using when you posted, he's using macOS Big Sur. May 30 '21 at 4:16
0

Here's one inelegant way to do it, adapted from a decade-old SO answer:

open_this_tab() {
    rand_string=$(openssl rand -base64 12)
    echo $rand_string
    osascript -e 'tell application "Terminal"
        set allWindows to number of windows

        repeat with i from 1 to allWindows
            set allTabs to number of tabs of window i
            repeat with j from 1 to allTabs
                if contents of tab j of window i contains '"\"$rand_string\""' then
                    set frontmost of window i to true
                    set selected of tab j of window i to true
                end if
            end repeat
        end repeat
        end tell'
}

Testing it out:

sleep 3
# (go to a different window or tab)
open_this_tab

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .