Question

I wonder if anyone can help with this?

I have a bash script. It starts a sub-process which is another gui-based application. The bash script then goes into an interactive mode getting input from the user. This interactive mode continues indefinately. I would like it to terminate when the gui-application in the sub-process exits.

I have looked at SIGCHLD but this doesn't seem to be the answer. Here's what I've tried but I don't get a signal when the prog ends.

set -o monitor

"${prog}" &
prog_pid=$!

function check_pid {
    kill -0 $1 2> /dev/null
}

function cleanup {
    ### does cleanup stuff here
    exit
}


function sigchld {
    check_pid $prog_pid
    [[ $? == 1 ]] && cleanup
}

trap sigchld SIGCHLD

Updated following answers. I now have this working using the suggestion from 'nosid'. I have another, related, issue now which is that the interactive process that follows is a basic menu driven process that blocks waiting for key input from the user. If the child process ends the USR1 signal is not handled until after input is received. Is there any way to force the signal to be handled immediately?

The wait look looks like this:

stty raw                 # set the tty driver to raw mode 
max=$1                   # maximum valid choice
choice=$(expr $max + 1)  # invalid choice
while [[ $choice -gt $max ]]; do
    choice=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
done
stty sane                # restore tty

Updated with solution. I have solved this. The trick was to use nonblocking I/O for the read. Now, with the answer from 'nosid' and my modifications, I have exactly what I want. For completeness, here is what works for me:

#!/bin/bash -bm
{
"${1}"
kill -USR1 $$
} &

function cleanup {
    # cleanup stuff
    exit
}

trap cleanup SIGUSR1

while true ; do
   stty raw                 # set the tty driver to raw mode 
   max=9                    # maximum valid choice
   while [[ $choice -gt $max || -z $choice ]]; do
       choice=`dd iflag=nonblock if=/dev/tty bs=1 count=1 2>/dev/null`
   done
   stty sane                # restore tty

   # process choice       

done
Was it helpful?

Solution

Here is a different approach. Instead of using SIGCHLD, you can execute an arbitrary command as soon as the GUI application terminates.

{
    some_command args...
    kill -USR1 $$
} &

function sigusr1() { ... }

trap sigusr1 SIGUSR1

OTHER TIPS

Ok. I think I understand what you need. Have a look at my .xinitrc:

   xrdb ~/.Xdefaults
   source ~/.xinitrc.hw.settings
   xcompmgr &
   xscreensaver &
   # after starting some arbitrary crap we want to start the main gui.       

   startfluxbox &  PIDOFAPP=$! ## THIS IS THE IMPORTANT PART
   setxkbmap genja

   wmclockmon -bl &


   sleep 1
   wmctrl -s 3  && aterms sone &
   sleep 1
   wmctrl -s 0


   wait $PIDOFAPP ## THIS IS THE SECOND PART OF THE IMPORTANT PART

   xeyes -geometry 400x400+500+400 &
   sleep 2
   echo im out!

What happens is that after you send a process to the background, you can use wait to wait until the process dies. whatever is after wait will not be executed as long as the application is running. You can use this to exit after the GUI has been shut down.

PS: I run bash.

I think you need to do:

set -bm

or

set -o monitor notify

As per the bash manual:

-b
    Cause the status of terminated background jobs to be reported immediately, rather than before printing the next primary prompt.

The shell's main job is executing child processes, and it needs to catch SIGCHLD for its own purposes. This somehow restricts it to pass on the signal to the script itself.

Could you just check for the child pid and based on that send the alert. You can find the child pid as below-

bash_pid=$$
while true
do
    children=`ps -eo ppid | grep -w $bash_pid`
    if [ -z "$children" ]; then
        cleanup
        alert
        exit
    fi
done
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top