Reputation: 63
I neeed to do a bash script that runs a C program that spawns an n depth binary tree of processes using fork()
, then trims it level by level starting from the leaves of the tree up to the root.
The C code that makes the process tree is quite simple. You can see the full code here, but a TL;DR version is as follows:
void tree(int n):
if (n==0) exit
rchild=fork()
if (parent)
lchild=fork()
if (left child)
tree(n-1)
else //right child
tree(n-1)
sleep(1000)
looking at pstree -pn PID
output I noticed that the PIDs of the childs were consecutive, so I decided to kill the process by numeric value based upon the PID of the first instance. But maybe becasue of the commands taking up PID values or another system processes, running the code inside the script knocks off the values of the PIDs, so my approach no longer works. I'm trying to take the PIDs directly by using the output of pstree, but for now it seems that it will be a mess of sed
and awk
calls just to get one level of PIDs.
here is the bash script that I have so far:
#!/bin/bash
if [ ! -f "./fork.run" ]
then
>&2 echo 'Error: binary mising'
>&2 echo 'Generate it with "gcc -o fork.run fork.c"'
exit
fi
if [ "$1" == "" ]
then
>&2 echo "Error: you need to indicate the depth of the tree"
exit
fi
./fork.run $(( $1 - 1 )) &
fork=$! #store tree's PID
n=$1
echo "fork started with PID $fork"
while [ $n -gt 1 ]
do
echo "Tree of the process $fork:"
pstree -pn $fork
sleep 1
#calculation based on properties of the binary tree
min=$(( 2 ** (n - 1) + $fork ))
max=$(( (2 ** n) - 1 + $fork ))
echo "starting trim: level $n"
for i in `seq $min $max`
do
echo "killing $i"
kill $i #I also tried kill -9 $i, but it's the same.
done
sleep 1
echo "processes from $min to $max trimmed"
let n--
done
pstree -pn $fork
sleep 1
echo "starting trim: level $n (final)"
kill $fork
sleep 1
echo "initial process ($fork) trimmed"
Upvotes: 0
Views: 242
Reputation: 19395
it seems that it will be a mess of sed and awk calls just to get one level of PIDs.
Well, it's not all too messy with awk
. The following replacement of your while
loop processes the pstree
output with an awk
script which determines (on the basis of the position in each line) the tree levels to which the contained processes belong and kills the ones on the selected level n
.
while [ $n -gt 1 ]
do
echo "Tree of the process $fork:"
pstree -p $fork
sleep 1
echo "starting trim: level $n"
pstree -pl $fork |
gawk -vn=$n '
/^[^ ]/ { level = 1; start[1] = 1 } # line starting with non-space has top level
/^ / { level = trats[match($0, "[|`]-")] } # determine first level of line from position of |- or `-
{ while (i = match(substr($0, start[level]), ")-[-+]-"))
{ start[level+1] = start[level]+i+1; ++level; trats[start[level]] = level } # hash level by position
if (match(substr($0, start[n]), "^.-[^(]+.([0-9]+)", p)) { print "killing "p[1]; system("kill "p[1]) }
} '
sleep 1
echo "processes trimmed"
let n--
done
Upvotes: 1