Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to capture Ctrl-C and use it to exit an endless loop properly

Tags:

bash

sigint

wine

I'm trying to run a program inside an endless loop because it sometimes dies for no reason. I would like to be able to hit Ctrl-C to prevent the program being restarted though.

I don't want Ctrl-C to kill the program, just to wait until it dies, then not restart it again.

theprogram is a wine program (utorrent).

Bonus points for telling me how to make it so it will safely exit theprogram just like clicking on the 'x' in the top right of it. When I manually kill it from the command line or hit Ctrl-C, it doesn't get to run its cleanup code. Hence my attempt to just stop it being restarted.

I checked a few of the other questions about trapping SIGINT, but I couldn't work out how to do this.

Can anyone fix this code? My code seems to kill theprogram then exit the loop when Ctrl-C is pressed, without letting theprogram clean up.

#!/bin/bash

EXIT=0
trap exiting SIGINT

exiting() { echo "Ctrl-C trapped, will not restart utorrent" ; EXIT=1;}

while [ $EXIT -eq 0 ] ; do
        wine theprogram
        echo "theprogram killed or finished"
        date
        echo "exit code $?"
        echo "sleeping for 20 seconds, then restarting theprogram..."
        sleep 20
done

echo "out of loop"
like image 303
localhost Avatar asked Oct 27 '25 18:10

localhost


2 Answers

Use a monitoring process:

This allows the SIGINT signal to hit the monitor process trap handler without affecting the child.

(this could also be done in perl, python or any language)

#!/bin/bash

cmd() {
    trap '' INT
    trap 'echo "Signal USR1 received (pid=$BASHPID)"; EXIT=1' USR1
    EXIT=0
    while [ $EXIT -eq 0 ]
    do
        echo "Starting (pid=$BASHPID)..."
        sleep 5 # represents "wine theprogram"
        echo "theprogram killed or finished"
        date
        echo "Exit code $?"
        if [ $EXIT -eq 0 ]; then
            echo "Sleeping for 2 seconds, then restarting theprogram..."
            sleep 2
        fi
    done
    echo "Exiting (pid=$BASHPID)"
}

run() { cmd & PID=$!; echo Started $PID; }
graceful_exit() { kill -s USR1 $PID && echo "$PID signalled to exit (USR1)"; }
shutdown() { kill -0 $PID 2>/dev/null && echo "Unexpected exit, killing $PID" && kill $PID; }

trap 'graceful_exit' INT
trap 'shutdown' EXIT
run

while :
do
    wait && break
done

echo "Exiting monitor process"
like image 199
Curtis Yallop Avatar answered Oct 30 '25 08:10

Curtis Yallop


Try this:

while true
do
  xterm -e wine theprogram || break
  sleep 3
done

The trick is done by using another xterm to start the wine. That way the wine has a different controlling tty and won't be affected by the Ctrl-c press.

The drawback is that there will be an additional xterm lingering around on your desktop. You could use the option -iconic to start it iconified.

like image 21
Alfe Avatar answered Oct 30 '25 09:10

Alfe