How to check which program runs inside gnome-terminal - linux

I want to write a program which prints the current focused window name and if it is a gnome-terminal, then prints out the running program inside the current gnome-terminal tab (for example vim, if a vim session is running).
To get the currently focused window name, I used:
xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)"
xprop -id 0x220ad5a | grep "WM_CLASS(STRING)"
If the current window is a gnome-terminal, this will return 'gnome-terminal'.
But how can I find out the program running inside gnome-terminal (more precisely: inside the current gnome-terminal tab)? I thought about using dbus but gnome-terminal does not seem to support it.

I needed to solve the same problem and after some investigation I discovered
that wmctrl and pstree prints processes in the same order.
DISCLAIMER: I'm not sure this is always the case but in my case where I use this method to open up a "cheatsheet" for manual review a problem with it would be detected immediately and so for had no problem.
Here is a demo-script that when run will output the correct row of the pstree that corresponds to the currently active terminal window. For debugging it prints intermediate steps into ~/debug.txt
#!/bin/bash
winid=$(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW)/ {print $NF}' | xargs printf "%#010x\n")
echo 'winid:'$winid >> ~/debug.txt
winclass=$(xprop -id $winid | awk '/WM_CLASS/ {print $NF}')
niceclass=${winclass//\"/}
echo 'winclass:'$niceclass >> ~/debug.txt
if [ $niceclass == "Gnome-terminal" ]
then
terminalPID=$(xprop -id $winid | awk '/_NET_WM_PID/ {print $NF}')
echo 'winPID:'$terminalPID >> ~/debug.txt
# get inx of window for this PID
termInx=$(wmctrl -l -p | grep $terminalPID | awk '/'"$winid"'/ {print NR}')
echo 'term inx:'$termInx >> ~/debug.txt
# Take the childprocess of that inx and PID
shell_process=$(pstree -p $terminalPID | sed "s/.*(1998)//" | sed "s/\W*//" | awk 'NR=='$termInx)
pstree -p $terminalPID >> ~/debug.txt
echo 'found process:'$shell_process >> ~/debug.txt
echo 'found process:'$shell_process
fi
Expected output:
tony#tony-mini:~$ ./test_so.sh
found process:bash(8001)---test_so.sh(9869)---test_so.sh(9885)-+-awk(9889)
Then pick out the desired child.

Get the gnome terminal PID, and check which processes have this number as PPID.
I have answered a very similar question few days ago, see this link for details.

Thanks Adam! I am almost there. With xprop I can get the PID of the gnome-terminal (6736). But unfortunately, there is only one process for all gnome-terminal windows and tabs. See this pstree output with two opened gnome-terminal windows:
-gnome-terminal(6736)-+-bash(6738)---vim(6780)
| |-bash(7026)---pstree(7045)
| | `-{gnome-terminal}(6740)
Is there a way to find out the bash pid of the currently opened gnome-terminal tab?

Related

How to cleanup all unused screens?

I would like to remove from my systems all screens I've opened to do my tasks. But I need to get rid of the screens that aren't doing anything. I don't want to kill a screen that something happens inside.
As an example, I run a long command in one screen called screen3 while screens named screen1 and screen2 are previous screens, no jobs are running inside them. The goal is to have a command or script (in crontab) that automatically clean user1 and user2.
First attempt - detection only
screen -wipe > /dev/null
screen_pids=$(screen -ls | grep Detached | awk '/\.*\t/ {print strtonum($1)}')
for scr_pid in $screen_pids
do
bash_child=$(ps -el | grep $scr_pid | grep bash | awk '{print $4}')
if [ $(pgrep -P $bash_child | wc -l) -eq "0" ]; then
# in that case screen $scr_pid could be killed
echo "The screen $scr_pid doesn't have any child process and should be terminated"
fi
done

Display the name of all running processes in Linux in a file using a bash script

I need to display the name of all running processes in Linux in a file using a bash script. I wrote the code, but didnt succeed:
#!/bin/bash
for i in `ps aux| awk '{print $5}'`;
echo $i > /tmp/test;
done
Need your assistance, Thanks.
Using the for, the syntax is slightly different:
#!/bin/sh
cat /dev/null > /tmp/test
for i in $(ps aux | awk '{print $5}'); do
echo $i >> /tmp/test;
done
You missed the do operator
The output redirector > on a loop should change to appending >>, otherwise only the last value of the loop will be saved.
But as #stark said, the for is not required:
#!/bin/sh
ps aux | awk '{print $5}' > /tmp/test;
I'm not sure, what your output should look like. With your template, and the fixes from Glauco Leme, I only got the VSZ of all the processes.
I assume you need the cmd of each process, then you just can use ps -e --no-headers --format cmd.
In case you need it in a file:
ps -e --no-headers --format cmd > /tmp/test
I hope this will do what you need.

Awk not working inside bash script

Im trying to write a bash script and trying to take input from user and executing a kill command to stop a specific tomcat.
...
read user_input
if [ "$user_input" = "2" ]
then
ps -ef | grep "search-tomcat" |awk {'"'"'print $2'"'"'}| xargs kill -9
echo "Search Tomcat Shut Down"
fi
...
I have confirmed that the line
ps -ef | grep "search-tomcat"
works fine in script but:
ps -ef | grep "search-tomcat" |awk {'"'"'print $2'"'"'}
doesnt yield any results in script, but gives desired output in terminal, so there has to be some problem with awk command
xargs can be tricky - Try:
kill -9 $(ps -ef | awk '/search-tomcat/ {print $2}')
If you prefer using xargs then check man page for options for your target OS (i.e. xargs -n.)
Also noting that 'kill -9' is a non-graceful process exit mechanism (i.e. possible file corruption, other strangeness) so I suggest only using as a last resort...
:)

Can i wait for a process termination that is not a child of current shell terminal?

I have a script that has to kill a certain number of times a resource managed by a high avialability middelware. It basically checks whether the resource is running and kills it afterwards, i need the timestamp of when the proc is really killed. So i have done this code:
#!/bin/bash
echo "$(date +"%T,%N") :New measures Run" > /home/hassan/logs/measures.log
for i in {1..50}
do
echo "Iteration: $i"
PID=`ps -ef | grep "/home/hassan/Desktop/pcmAppBin pacemaker_app/MainController"|grep -v "grep" | awk {'print$2'}`
if [ -n "$PID" ]; then
echo "$(date +"%T,%N") :Killing $PID" >> /home/hassan/logs/measures.log
ps -ef | grep "/home/hassan/Desktop/pcmAppBin pacemaker_app/MainController"|grep -v "grep" | awk {'print "kill -9 " $2'} | sh
wait $PID
else
PID=`ps -ef | grep "/home/hassan/Desktop/pcmAppBin pacemaker_app/MainController"|grep -v "grep" | awk {'print$2'}`
until [ -n "$PID" ]; do
sleep 2
PID=`ps -ef | grep "/home/hassan/Desktop/pcmAppBin pacemaker_app/MainController"|grep -v "grep" | awk {'print$2'}`
done
fi
done
But with my wait command i get the following error message: wait: pid xxxx is not a child of this shell
I assume that You started the child processes from bash and then start this script to wait for. The problem is that the child processes are not the children of the bash running the script, but the children of its parent!
If You want to launch a script inside the the current bash You should start with ..
An example. You start a vim and then You make is stop pressing ^Z (later you can use fg to get back to vim). Then You can get the list of jobs by using the˙jobs command.
$ jobs
[1]+ Stopped vim myfile
Then You can create a script called test.sh containing just one command, called jobs. Add execute right (e.g. chmod 700 test.sh), then start it:
$ cat test.sh
jobs
~/dev/fi [3:1]$ ./test.sh
~/dev/fi [3:1]$ . ./test.sh
[1]+ Stopped vim myfile
As the first version creates a new bash session no jobs are listed. But using . the script runs in the present bash script having exactly one chold process (namely vim). So launch the script above using the . so no child bash will be created.
Be aware that defining any variables or changing directory (and a lot more) will affect to your environment! E.g. PID will be visible by the calling bash!
Comments:
Do not use ...|grep ...|grep -v ... |awk --- pipe snakes! Use ...|awk... instead!
In most Linux-es you can use something like this ps -o pid= -C pcmAppBin to get just the pid, so the complete pipe can be avoided.
To call an external program from awk you could try system("mycmd"); built-in
I hope this helps a bit!

Suppress Notice of Forked Command Being Killed

Let's suppose I have a bash script (foo.sh) that in a very simplified form, looks like the following:
echo "hello"
sleep 100 &
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"
The third line imitates pkill, which I don't have by default on Mac OS X, but you can think of it as the same as pkill. However, when I run this script, I get the following output:
hello
foo: line 4: 54851 Killed sleep 100
bye
How do I suppress the line in the middle so that all I see is hello and bye?
While disown may have the side effect of silencing the message; this is how you start the process in a way that the message is truly silenced without having to give up job control of the process.
{ command & } 2>/dev/null
If you still want the command's own stderr (just silencing the shell's message on stderr) you'll need to send the process' stderr to the real stderr:
{ command 2>&3 & } 3>&2 2>/dev/null
To learn about how redirection works:
From the BashGuide: http://mywiki.wooledge.org/BashGuide/TheBasics/InputAndOutput#Redirection
An illustrated tutorial: http://bash-hackers.org/wiki/doku.php/howto/redirection_tutorial
And some more info: http://bash-hackers.org/wiki/doku.php/syntax/redirection
And by the way; don't use kill -9.
I also feel obligated to comment on your:
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
This will scortch the eyes of any UNIX/Linux user with a clue. Moreover, every time you parse ps, a fairy dies. Do this:
kill $!
Even tools such as pgrep are essentially broken by design. While they do a better job of matching processes, the fundamental flaws are still there:
Race: By the time you get a PID output and parse it back in and use it for something else, the PID might already have disappeared or even replaced by a completely unrelated process.
Responsibility: In the UNIX process model, it is the responsibility of a parent to manage its child, nobody else should. A parent should keep its child's PID if it wants to be able to signal it and only the parent can reliably do so. UNIX kernels have been designed with the assumption that user programs will adhere to this pattern, not violate it.
How about disown? This mostly works for me on Bash on Linux.
echo "hello"
sleep 100 &
disown
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"
Edit: Matched the poster's code better.
The message is real. The code killed the grep process as well.
Run ps ax | grep sleep and you should see your grep process on the list.
What I usually do in this case is ps ax | grep sleep | grep -v grep
EDIT: This is an answer to older form of question where author omitted the exclusion of grep for the kill sequence. I hope I still get some rep for answering the first half.
Yet another way to disable job termination messages is to put your command to be backgrounded in a sh -c 'cmd &' construct.
And as already pointed out, there is no need to imitate pkill; you may store the value of $! in another variable instead.
echo "hello"
sleep_pid=`sh -c 'sleep 30 & echo ${!}' | head -1`
#sleep_pid=`sh -c '(exec 1>&-; exec sleep 30) & echo ${!}'`
echo kill $sleep_pid
kill $sleep_pid
echo "bye"
Have you tried to deactivate job control? It's a non-interactive shell, so I would guess it's off by default, but it does not hurt to try... It's regulated by the -m (monitor) shell variable.

Resources