Problem
I need to find what process is running on a particular window in screen (in a reasonable amount of time).
Scenario
I need to use the Session Name and Window Title to find the process running therein. It needs to not be super slow.
Also potentially noteworthy: I'm using byobu as a wrapper for screen.
What I've tried
- Searching the internet
- Reading the screen man page (not for the faint of heart). (Okay, I didn't read all of it, but I did most of the relevant sections and searched it very thoroughly for anything that might be useful.)
- What I learned:
- The only way to gain the information I might need from screen (by calling screen) is through the use of it's command line flags.
- -Q will allow you to query certain commands, but none of these provided everything that I need. The one that I'm using returns the Window number.
- number - what I'm using to get the window number
- windowlist - allows you to get a custom-formatted string of information, but the session PID is not one of the things you can ask for
- echo, info, lastmsg, select, time, title are the other ones and none of these looked useful
- -ls lists the active sessions. It prepends the PID to the session name, so this is how I'm currently getting the session PID.
- -Q will allow you to query certain commands, but none of these provided everything that I need. The one that I'm using returns the Window number.
- Once I have the PID of the shell running in a specific Window, I can check its environment variables for WINDOW. This variable is set to the window number. This is what I'm using to match the process to the window.
- There is no single command that will allow me to return the session PID and a map of the window titles to window numbers. Also, I could find no way to deterministically find the session id and window title to window number map outside of calling screen.
- The only way to gain the information I might need from screen (by calling screen) is through the use of it's command line flags.
- What I learned:
- Trial and error / digging through environment variables
- Writing a script
My Script
I wrote a script that seems to successfully solve the problem, but it takes a little over 0.75 seconds to run. This is far too long for what I need done, but more importantly, far too long when a server is waiting for its completion to send the response to an HTML request.
Here is the script:
#!/bin/bash
# Accept the name of a GNU/screen session & window and return the process running in its shell
SessionName=$1
TabName=$2
# ====== Averages 0.370 seconds ======
# This finds the window number given the session name and window title
# The screen command queries screen for the window number of the specified
# window title in the specified session.
# Example output of screen command: 1 (Main)
# Example output after cut command: 1
TargetTabNum=$(screen -S $SessionName -p $TabName -Q number | cut -d ' ' -f1)
# ====== Averages 0.370 seconds ======
# This finds the session PID given the session name.
# The screen command prints the list of session IDs
# Example output of screen command:
# There is a screen on:
# 29676.byobu (12/09/2019 10:23:19 AM) (Attached)
# 1 Socket in /run/screen/S-{username here}.
# Example output after sed command: 29676
SessionPID=$(screen -ls | sed -n "s/\s*\([0-9]*\)\.$SessionName\t.*/\1/p")
# ====== The rest averages 0.025 seconds ======
# This gets all the processes that have the session as a parent,
# loops through them checking the WINDOW environment variable for
# each until it finds the one that matches the window title, and
# then finds the process with that process as a parent and prints its
# command and arguments (or null if there are no matching processes)
ProcessArray=( $(ps -o pid --ppid $SessionPID --no-headers) )
for i in "${ProcessArray[@]}"
do
ProcTabNum=$(tr '\0' '\n' < /proc/$i/environ | grep ^WINDOW= | cut -d '=' -f2)
if [ ! -z "$ProcTabNum" ] && [ "$TargetTabNum" -eq "$ProcTabNum" ]; then
ProcInTab=$(ps -o cmd --ppid $i --no-headers)
if [[ $? -eq 1 ]]; then
ProcInTab=NULL
fi
echo $ProcInTab
exit 0
fi
done
echo "Couldn't find the specified Tab: $TabName" >&2
exit 1
As you can see, the problem commands are the two screen commands. I can get rid of one of them by searching for a screen process launched with the session name, but this feels kind of flaky and I'm not sure it would be deterministic:
SessionPID=$(ps -eo pid,command --no-headers | grep -i "[0-9]* screen.*\-s $SessionName " | grep -v grep | cut -d ' ' -f1)
Goal
I would like to have a fast, reliable way to determine the process currently running in a specific screen window. I feel like I'm just missing something, so I would be very grateful if one of you spot it!
(I'm still fairly knew to StackExchange, so any feedback on my question is welcome!)
int system(const char *command);
or another fast compiled language. Those should speed it up as long as the screen command itself is not the actual bottleneck. That seems to be the case, but I would test the screen command on its own (no piping) before concluding this. If the screen command is the botleneck then you can try to use an screen API if it exists, or find a feature of the process that indicates is running in screen.while
loop coupled with asleep
command.