How to get all parent processes and all subprocesses with `pstree` - linux

Command pstree PID can show all subprocess information of the process specified by PID. However, I also want to know all parent process information of the process PID, how can I get it?
An example:
init
|- parent_process
| `- current_process
| |- subprocess_1
| `- subprocess_2
`- other_process
What I want is when I run pstree current_process_pid, I want to get below output:
init
`- parent_process
`- current_process
|- subprocess_1
`- subprocess_2
When I run pstree subprocess_1_pid, it will output:
init
`- parent_process
`- current_process
`- subprocess_1

# With my psmisc 22.20:
pstree -p -s PID
Maybe if with ps -ef:
awk -vPID=$1 '
function getParent ( pid ) {
if (pid == "" || pid == "0") return;
while ("ps -ef | grep "pid | getline) {
if ($2 == pid) {
print $8"("$2") Called By "$3;
getParent($3);
break;
}
}
close ("ps -ef")
}
BEGIN { getParent(PID) }
'
This is ugly assuming ps output column and order. Actually one single run of ps -ef contains all info needed.
This don't worth the time, I still recommend updating psmisc, it won't hurt.
EDIT: A mimic using single run ps -ef:
ps -ef | awk -vPID=$1 '
function getpp ( pid, pcmd, proc ) {
for ( p in pcmd ) {
if (p == pid) {
getpp(proc[p], pcmd, proc);
if (pid != PID) printf("%s(%s)───", pcmd[pid], pid);
}
}
}
NR > 1 {
# pid=>cmd
pcmd[$2] = $8;
# pid=>Parent
pproc[$2] = $3;
}
END {
getpp(PID, pcmd, pproc);
printf "\n";
system("pstree -p "PID);
}'

I found laps options mentioned by #haridsv (pstree -laps <pid>) being a solution. It was a bit verbose for me though, so I'd stick to a shorter aps output.
To get the process tree of the current process (its ID is $$ in Bash):
pstree -aps $$
That prints the process tree like this:
systemd,1
└─kitty,86739
└─bash,86742
└─pstree,86904 -aps 86742

Related

Bash script to get specific user(s) id and processes count

I need bash script to count processes of SPECIFIC users or all users. We can enter 0, 1 or more arguments. For example
./myScript.sh root deamon
should execute like this:
root 92
deamon 8
2 users has total processes: 100
If nothing is entered as parameter, then all users should be listed:
uuidd 1
awkd 2
daemon 1
root 210
kklmn 6
5 users has total processes: 220
What I have till now is script for all users, and it works fine (with some warnings). I just need part where arguments are entered (some kind of filter results). Here is script for all users:
cntp = 0 #process counter
cntu = 0 #user counter
ps aux |
awk 'NR>1{tot[$1]++; cntp++}
END{for(id in tot){printf "%s\t%4d\n",id,tot[id]; cntu++}
printf "%4d users has total processes:%4d\n", cntu, cntp}'
#!/bin/bash
users=$#
args=()
if [ $# -eq 0 ]; then
# all processes
args+=(ax)
else
# user processes, comma-separated list of users
args+=(-u${users// /,})
fi
# print the user field without header
args+=(-ouser=)
ps "${args[#]}" | awk '
{ tot[$1]++ }
END{ for(id in tot){ printf "%s\t%4d\n", id, tot[id]; cntu++ }
printf "%4d users has total processes:%4d\n", cntu, NR}'
The ps arguments are stored in array args and list either all processes with ax or user processes in the form -uuser1,user2
and -ouser= only lists the user field without header.
In the awk script I only removed the NR>1 test and variable cntp which can be replaced by NR.
Possible invocations:
./myScript.sh
./myScript.sh root daemon
./myScript.sh root,daemon
The following seems to work:
ps axo user |
awk -v args="$(IFS=,; echo "$*")" '
BEGIN {
# split args on comma
split(args, users, ",");
# associative array with user as indexes
for (i in users) {
enabled[users[i]] = 1
}
}
NR > 1 {
tot[$1]++;
cntp++;
}
END {
for(id in tot) {
# if we passed some arguments
# and its disabled
if (length(args) && enabled[id] == 0) {
continue
}
printf "%s\t%4d\n", id, tot[id];
cntu++;
}
printf "%4d users has total processes:%4d\n", cntu, cntp
}
'
Tested in repl.

How to get Windowid from PID from a electron Application

I want to get the WindowID from the PID of an Electron Process (for example riot-desktop)
I tried to get it with xdotools like this:
$ xdotool search --pid $(pgrep riot)
nothing is printed
$ pgrep riot
30461
$ xdotool search --pid 30461
nothing is printed again
You have to search for the pid of the subprocess of electron.
You can get the pid of the subprocess with:
PID=$(ps h -C electron | grep riot | cut -f1 -d"?")
now you can search for the pid
xdotool search --pid $PID
you can combine both commands to a single command
xdotool search --pid $(ps h -C electron | grep riot | grep witzerstorfer | cut -f1 -d"?")
if your ps returns multiple pid's you have to add more grep commands, for example if you work with profiles the command could look like this:
PID=$(ps h -C electron | grep riot | grep $PROFILENAME | cut -f1 -d"?")
If you want to find windowID of your electron application then you can use
win.getMediaSourceId()
Returns String - Window id in the format of DesktopCapturerSource's id. For example "window:1324:0".
More precisely the format is window:id:other_id where id is HWND on Windows, CGWindowID (uint64_t) on macOS and Window (unsigned long) on Linux. other_id is used to identify web contents (tabs) so within the same top level window.
Example:
// In the main process.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
// Load a remote URL
win.loadURL('https://github.com')
// Or load a local HTML file
win.loadURL(`file://${__dirname}/app/index.html`)
// Print window id
console.log('window id is', win.getMediaSourceId())

Linux tee command occasionally fails if followed by a pipe

I run a find command with tee log and xargs process output; by accident I forget add xargs in second pipe and found this question.
The example:
% tree
.
├── a.sh
└── home
└── localdir
├── abc_3
├── abc_6
├── mydir_1
├── mydir_2
└── mydir_3
7 directories, 1 file
and the content of a.sh is:
% cat a.sh
#!/bin/bash
LOG="/tmp/abc.log"
find home/localdir -name "mydir*" -type d -print | tee $LOG | echo
If I add the second pipe with some command, such as echo or ls, the write log action would occasionally fail.
These are some examples when I ran ./a.sh many times:
% bash -x ./a.sh; cat /tmp/abc.log // this tee failed
+ LOG=/tmp/abc.log
+ find home/localdir -name 'mydir*' -type d -print
+ tee /tmp/abc.log
+ echo
% bash -x ./a.sh; cat /tmp/abc.log // this tee ok
+ LOG=/tmp/abc.log
+ find home/localdir -name 'mydir*' -type d -print
+ tee /tmp/abc.log
+ echo
home/localdir/mydir_2 // this is cat /tmp/abc.log output
home/localdir/mydir_3
home/localdir/mydir_1
Why is it that if I add a second pipe with some command (and forget xargs), the tee command will fail occasionally?
The problem is that, by default, tee exits when a write to a pipe fails. So, consider:
find home/localdir -name "mydir*" -type d -print | tee $LOG | echo
If echo completes first, the pipe will fail and tee will exit. The timing, though, is imprecise. Every command in the pipeline is in a separate subshell. Also, there are the vagaries of buffering. So, sometimes the log file is written before tee exits and sometimes it isn't.
For clarity, let's consider a simpler pipeline:
$ seq 10 | tee abc.log | true; declare -p PIPESTATUS; cat abc.log
declare -a PIPESTATUS='([0]="0" [1]="0" [2]="0")'
1
2
3
4
5
6
7
8
9
10
$ seq 10 | tee abc.log | true; declare -p PIPESTATUS; cat abc.log
declare -a PIPESTATUS='([0]="0" [1]="141" [2]="0")'
$
In the first execution, each process in the pipeline exits with a success status and the log file is written. In the second execution of the same command, tee fails with exit code 141 and the log file is not written.
I used true in place of echo to illustrate the point that there is nothing special here about echo. The problem exists for any command that follows tee that might reject input.
Documentation
Very recent versions of tee have an option to control the pipe-fail-exit behavior. From man tee from coreutils-8.25:
--output-error[=MODE]
set behavior on write error. See MODE below
The possibilities for MODE are:
MODE determines behavior with write errors on the outputs:
'warn' diagnose errors writing to any output
'warn-nopipe'
diagnose errors writing to any output not a pipe
'exit' exit on error writing to any output
'exit-nopipe'
exit on error writing to any output not a pipe
The default MODE for the -p option is 'warn-nopipe'. The default
operation when --output-error is not specified, is to exit immediately
on error writing to a pipe, and diagnose errors writing to non pipe
outputs.
As you can see, the default behavior is "to exit immediately
on error writing to a pipe". Thus, if the attempt to write to the process that follows tee fails before tee wrote the log file, then tee will exit without writing the log file.
Right, piping from tee to something that exits early (not dependent on reading the input from tee in your case) will cause intermittent errors.
For a summary of this gotcha see:
http://www.pixelbeat.org/docs/coreutils-gotchas.html#tee
I debugged the tee source code, but I'm not familiar with Linux C, so maybe have problems.
tee belongs to coreutils package, under src/tee.c
First, it set buffer with:
setvbuf (stdout, NULL, _IONBF, 0); // for standard output
setvbuf (descriptors[i], NULL, _IONBF, 0); // for file descriptor
So it is unbuffer?
Second, tee put stdout as its first item in descriptor array, and will write to descriptor with for loop:
/* In the array of NFILES + 1 descriptors, make
the first one correspond to standard output. */
descriptors[0] = stdout;
files[0] = _("standard output");
setvbuf (stdout, NULL, _IONBF, 0);
...
for (i = 0; i <= nfiles; i++) {
if (descriptors[i]
&& fwrite (buffer, bytes_read, 1, descriptors[i]) != 1) // failed!!!
{
error (0, errno, "%s", files[i]);
descriptors[i] = NULL;
ok = false;
}
}
such as tee a.log, descriptors[0] is stdout, and descriptors[1] is a.log.
As #John1024 said, pipeline is parallel (what I misunderstand before). The second pipe command, such as echo, ls, or true, not accept input, so it would not "wait" for the input, and if it execute faster, it will close the pipe (input end) before tee write to output end, so above code, the comment line will failed not not go on writing to file descriptor.
Supply:
The strace result with killed by SIGPIPE:
write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n", 21) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=22649, si_uid=1000} ---
+++ killed by SIGPIPE +++

prstat in Ubuntu or Centos

As the Java Performance said:
Solaris prstat has additional capabilities
such as reporting both user and kernel or system CPU utilization along with other
microstate information using the prstat -m and -L options. The -m option prints
microstate information, and -L prints statistics on per lightweight process.
There is any tool available like prstat in Centos or Ubuntu ?
I believe the Linux commands you are looking for are top and pstree .
Here is ptree for Linux,
#!/bin/sh
# Solaris style ptree
[ -x /usr/bin/ptree ] && exec /usr/bin/ptree "$#"
# Print process tree
# $1 = PID : extract tree for this process
# $1 = user : filter for this (existing) user
# $1 = user $2 = PID : do both
PATH=/bin:/usr/bin:/usr/sbin:/sbin
export PATH
psopt="-e"
case $1 in
[a-z]*) psopt="-u $1";shift;;
esac
[ -z "$1" ] &&
exec ps $psopt -Ho pid=,args=
#some effort to add less to the ps list
tmp=/tmp/ptree.$$
trap 'rm $tmp' 0 HUP INT TERM
ps $psopt -Ho pid=,args= >$tmp
<$tmp awk '
{ ci=index(substr($0,7),$2); o[ci]=$0 }
ci>s[a] { s[++a]=ci }
$1==pid {
for(i=1;i<=a;i++) {
si=s[i]; if(si<=ci) print o[si]
}
walkdown=ci
next
}
ci<walkdown { exit }
walkdown!=0 { print }
' pid="$1"
There is no prstat "equivalent" tool in Linux. You can use a combination of top and ps (or /proc/$pid/ resources) to get some useful result; maybe writing a shell script (using grep, sed and awk) which collects results from above commands and files.
Just for reference I found this link about top command and kernel, user and idle CPU utilization intresting
http://blog.scoutapp.com/articles/2015/02/24/understanding-linuxs-cpu-stats
Hope this helps.

Getting the Process ID of another program in Groovy using 'command slinging'

import java.lang.management.*
final String name = ManagementFactory.getRuntimeMXBean().getName();
final Integer pid = Integer.parseInt(name[0..name.indexOf("#")-1])
I tried this in my code but that gets the pid of the running program. I am running a sleeping script (all it does is sleep) called sleep.sh and i want to get the pid of that. Is there a way to do that? I have not found a very good way myself.
I also used a ps | grep and i can see the process id is there a way to output it though?
Process proc1 = 'ps -ef'.execute()
Process proc2 = 'grep sleep.sh'.execute()
Process proc3 = 'grep -v grep'.execute()
all = proc1 | proc2 | proc3
is there a way i can modify the all.text to get the process id or is there another way to get it?
Object getNumber(String searchProc) {
//adds the process in the method call to the grep command
searchString = "grep "+searchProc
// initializes the command and pipes them together
Process proc1 = 'ps -ef'.execute()
Process proc2 = searchString.execute()
Process proc3 = 'grep -v grep'.execute()
all = proc1 | proc2 | proc3
//sets the output to the piped commands to a string
output = all.text
//trims down the string to just the process ID
pid = output.substring(output.indexOf(' '), output.size()).trim()
pid = pid.substring(0, pid.indexOf(' ')).trim()
return pid
}
This is my solution. (I wanted to make it a method so i put the method declaration at the very top)
My problem at the beginning was that there was more spaces than one between the process name and the pid. but then i found the trim method and that worked nicely. If you have questions on my method let me know. I will check back periodically.

Resources