SCRIPT GOAL: the script is invoked as ./script.sh cmd1 cmd2 ... cmdn
. It should executes in background all the commands passed as arguments from the command line and check when all of them have finished their execution.
Furthermore if the SIGTERM signal is send to the script it should kill all the aforemoentioned processes (cmd1 ... cmdn
) and then kill himself.
PROBLEM: All seem working except the autotermination and I can't figure out why.
I tried to use kill $$
but at runtime I get segmentation fault
.
I was thinking that the problem was related to the fact that kill
command is inside a function but on the other hand if I comment kill $$
and I leave kill ${PIDAR[*]}
command, the latter work.
Could somebody explain me what I am missing?
#!/bin/bash
# signal handler
killemall () {
echo $$
kill ${PIDAR[*]}
kill $$ # implicated line
}
PIDAR=() # pid array
STAR=() # process state array
# execute processes in bg and save their pid
for i in "$@" ; do
$i &
PIDAR+=($!)
done
trap 'killemall' SIGTERM
terminated=1 # flag to indicate when all processes are terminated
while sleep 1 && [ $terminated -eq 1 ]; do
for (( i=0; i<${#PIDAR[*]}; i++ )); do
STAR[$i]=$(ps hp ${PIDAR[$i]} | awk '{ print $3 }')
if [ -z ${STAR[$i]} ]; then
terminated=0
else terminated=1
fi
echo "Process state ${PIDAR[$i]}:${STAR[$i]}" | tee -a logg
done
done
echo "All processes are terminated"
Thanks
SOLUTION: as user18197 pointed out, the problem is calling kill $$
.
Indeed as the kill
man page reports:
The default signal for kill is TERM
Then at each kill $$
invocation the script was calling the handler killemall
which in turn was invoking again kill $$
and so on recursively.
To avoid this behaviour we can untrap SIGTERM
signal. As help trap
reports:
If ARG is absent (and a single SIGNAL_SPEC is supplied) or `-', each specified signal is reset to its original value.
So the new function body is:
killemall () {
echo $$
trap - SIGTERM
kill ${PIDAR[@]}
kill $$
}