2

Background

I want to obtain the pid of a specific Terminal window.

ps -A | grep -w Terminal.app | grep -v grep | awk '{print $1}'

However, the above grabs the pid of the entire application and not of a specific tab or window that is running.

In Linux, one could execute the following:

x-terminal-emulator -e "cd $HOME ; sleep 10"

ps ax | \
    grep -v "grep" | \
    grep "sh -c" | grep "cd $HOME ; sleep 10" \
    xargs | \
    cut -d ' ' -f 1

Issue

Given the below terminal bash command, which opens a new terminal window and closes it much like x-terminal-emulator does.

How would I attempt to grab the pid of the window opened via the terminal command using ps like in the Linux example?

terminal:

#!/bin/bash

# Open new terminal window from the command line using v3 syntax for applescript as needed in terminal Version 3+
# This script blocks until the cmd is executed in the new terminal window then closes the new terminal window.
#
# Usage:
#     terminal                   Opens the current directory in a new terminal window
#     terminal [PATH]            Open PATH in a new terminal window
#     terminal [CMD]             Open a new terminal window and execute CMD
#     terminal [PATH] [CMD]      Opens a new terminal window @ the PATH and executes CMD
#
# Example:
#     terminal ~/Code/HelloWorld ./setup.sh
#

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

function terminal() {
    local cmd=""
    local wd="$PWD"
    local args="$*"

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

    if [ -d "$1" ]; then
        wd="$1"
        args="${*:2}"
    fi

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

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

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

terminal "$@"
  • echo $$ seems to return the tab/window pid for me on Mojave. See How does a Linux/Unix Bash script know its own PID? – lx07 Jan 21 at 17:39
  • 1
    @lx07 True, but that requires you to be in the context of the window in question. If I use ps for example, like the Linux example I provided, then I am able to obtain it from outside of the window. – Nicholas Adamou Jan 21 at 17:45
  • 1
    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. – CJK Jan 21 at 18:29
  • 1
    If your script is terminal.sh and you invoke it with ./terminal.sh "cd $HOME ; sleep 1000" you can get the pid of the window it opens (from elsewhere) with ps ax | grep -v grep | grep -v ./terminal.sh | grep 'sleep 1000' | awk '{print $1}'. (Not grep "cd $HOME ; sleep 1000" as in your example as ps only shows last command passed to terminal.sh). Is that what you mean? – lx07 Jan 21 at 18:41
  • @lx07 Yes, that is what I meant. – Nicholas Adamou Jan 21 at 19:11
0

Invoking your terminal.sh script using ./terminal.sh "cd $HOME ; sleep 1000" you can get the PID of the window opened which is running the sleep command using this:

ps ax | \
    grep 'sleep 1000' | \
    grep -v grep | \
    grep -v ./terminal.sh | \    
    awk '{print $1}'

If you try ps ax | grep 'sleep 1000' (or whatever command terminal.sh is running) you will see 3 returned:

A1398%  ps ax | grep 'sleep 1000'
 8263 s000  S+     0:00.01 /bin/bash ./terminal.sh cd /Users/XXXX ;  sleep 1000
 8272 s004  R+     0:00.00 grep sleep 1000
 8270 s005  S+     0:00.00 sleep 1000

The first is the command running in the window where terminal.sh is running, the second is the current window running ps ax | grep 'sleep 1000' and the last is the window actually opened by the terminal.sh command.

To get your windows PID therefore additionally exclude grep and terminal.sh


In the picture below:

  1. iTerm window showing ps ax | grep s00 before calling terminal.sh
  2. iTerm window running ./terminal.sh "cd $HOME ; sleep 1000"
  3. Terminal window opened by terminal.sh if none already open.
  4. Terminal window opened by terminal.sh running sleep or whatever the passed command.
  5. iTerm window run showing ps ax | grep s00 after. ps ax | grep 'sleep 1000' | grep -v grep | grep -v terminal.sh | awk '{print $1}' shows window 4.

Screenshot

Note that your terminal.sh command will open an extra terminal window (3) if none are already open. This window is not closed again on completion by the script although window (4) is.

| improve this answer | |
  • That's a lot of grep-ing. It would probably be simpler, quicker, and more reliable to obtain add a ppid column next to the pid for each process. That allows you to see which pid spawned each child. Also, since we know there is definitely going to be a controlling terminal running the program, the x flag is giving you a lot of the gaff you then work so hard to grep out. The a flag is unlikely to be needed either. – CJK Jan 22 at 14:20
1

Use echo $$. Mac OS is a unixy box and so $$ is an alias for myPid.

As you can see I am first showing all the shells (I use zsh) running at the moment. Below that you can see that echo $$ shows the PID of the pre-existing shell and not something new.

~ % ps aux | grep zsh ram 30724 0.8 0.0 4869828 5888 s003 S 9:28AM 0:00.35 -zsh ram 29765 0.0 0.0 4868884 8 s002 S+ 5:12PM 0:00.40 -zsh ram 29654 0.0 0.0 5028628 8 s001 S+ 4:52PM 0:00.49 -zsh ram 8001 0.0 0.0 4793028 8 s000 S+ 13Jan20 0:00.70 -zsh ram 30782 0.0 0.0 4258888 200 s003 R+ 9:29AM 0:00.00 egrep --color=auto zsh

~ % echo $$ 30724 ~ %

| improve this answer | |
  • Doesn't work in this case unfortunately. As the Bash Reference Manual states "($$) Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell." and indeed here $$ gives the pid of the calling process not the opened window. – lx07 Jan 22 at 10:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.