3

Background

Given the below terminal script, I want to modify the osascript so that instead of targeting the front window I am targeting the specific window that is opened from the AppleScript.

terminal:

#!/bin/bash

# Usage:
#     terminal [CMD]             Open a new terminal window and execute CMD
#
# Example:
#     terminal cd "sleep 100"

terminal() {

    # Mac OS only
    [ "$(uname -s)" != "Darwin" ] && {
        echo 'Mac OS Only'
        return
    }

    local cmd=""
    local args="$*"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    if [ -n "$args" ]; then
        cmd="$args"
    fi

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    osascript <<EOF
tell application "Terminal" to tell the front window
    set w to do script "$cmd"
    repeat
        delay 1
        if not busy of w then exit repeat
    end repeat
    close it
end tell
EOF

}

terminal "$@"

Issue

Currently, because of the use of front window I could change the focus after the window pops up to another terminal window then when the do script task completes close it will close the window I am currently focusing and not the window that actually ran the do script.

Ideas

One idea I had in mind was to modify the AppleScript so that we get the window id of the window created from the AppleScript like the below. However, close W does not work.

tell application "Terminal"
    set W to do script ""
    activate
    set S to do script "sleep 5" in W
    repeat
        delay 1
        if not busy of S then exit repeat
    end repeat
    close W
end tell

2 Answers 2

2

Based on this stackexchange answer you can store the window object then loop through.

You can then close the window you opened whether it is in focus or not.

    osascript <<EOF
    tell application "Terminal"
        set newTab to do script
        set current settings of newTab to settings set "Grass"
        set theWindow to first window of (every window whose tabs contains newTab)

        do script "$cmd" in newTab
        repeat
            delay 0.05
            if not busy of newTab then exit repeat
        end repeat

        repeat with i from 1 to the count of theWindow's tabs
            if item i of theWindow's tabs is newTab then close theWindow
        end repeat
    end tell
EOF

The set current settings of newTab to settings set "Grass" line isn't necessary - it is only to show the relevant window in a different colour.

1
  • 1
    Apologies for the delay. The thing I noticed is the repeat loop where you reference theWindow's tabs explicitly, thus forcing the collection to be enumerated in every iteration of the loop. Instead, you could assign theWindow's tabs to a variable beforehand, then reference the for the count and the item i of…. In this case, there's only ever one tab, so it doesn't matter, but it in other situations, it'll be quicker and less work for AppleScript. Or, a repeat loop of the form repeat with T in theWindow's tabs means you only need if T = newTab then..., which is quicker still.
    – CJK
    Jan 30, 2020 at 3:32
4

The way to do this is very simple, and I left a comment to this effect against an earlier question:

Depending what you wish to do, you might find the value of w in your AppleScript to be useful. The window that is created by do script returns an AppleScript reference to it (that you have assigned to w), which will be of the form tab 1 of window id <number>, where <number> is a five-or-so digit id number that remains fixed throughout the lifespan of the window. You have to ignore the fact that the reference always contains tab 1 of..., which is misleading since three tabs contained in a single window will all be tab 1 of... three distinct id numbers.

As you noticed, the close command does not apply to a tab, so you need the window id. The reference created from any do script command gives you tab 1 of window id..., so you will always be able to reference the window which any particular do script command is running in:

tell application id "com.apple.Terminal"
    set T to do script "echo $$" --> btw, there's the pid number of the window's sub-shell
    set W to the id of window 1 where its tab 1 = T
        .
        .
     (* doing other stuff *)
        .
        .
    close window id W
end tell
9
  • This is neater than my answer
    – lx07
    Jan 24, 2020 at 12:02
  • That’s nice of you to say. I already knew how to do it, and I think it’s a specific enough edge case you would probably only know if you have had to do it before. Do you mind me providing a couple of notes about your script or is that patronising ?
    – CJK
    Jan 25, 2020 at 6:43
  • If you have time please do - I'm a beginner at AppleScript.
    – lx07
    Jan 25, 2020 at 7:36
  • @CJK hi, set W to the id of window 1 where its tab 1 = T line leads to an error "Terminal got an error: AppleEvent handler failed." number -10000 error. Any idea why that might be? I checked and T is in the form you described "Tab 1 of Window #".
    – Halil Sen
    Nov 24, 2023 at 16:56
  • @HalilSen, almost all (or, in fact, probably all) AppleScript errors that return error number -10000 are not caused by something the script is doing wrong in and of itself, but rather something that has gone wrong under the hood with AppleScript itself, often due to some object reference that gets handled incorrectly when messaging an application. Sometimes, a simple refactoring (syntactical changes that don't alter how the code functions) is all it takes to get around the problem, but it can require implementing a new approach altogether if that's an option. Cont'd...
    – CJK
    Nov 25, 2023 at 20:11

You must log in to answer this question.

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