Question

I want to execute some commands on the end of the bash script, even if the user press CTRL+C to cancel its execution.

I know I can run the bash script from inside another programming language (for example, Python), so that I can use the 'finally' (try-finally) block to execute some code.

But knowing that StackOverflow is a center for exchanging fabulous ideas, I'm asking if is there a way to do what I want from inside my bash script.

So, ideas?

EDIT:

What I want is kill every proccess opened within my bash, i.e., selenium and Xvfb proccesses.

I tried writing this to the code:

 trap "selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}');for pid in $selenium_pids; do kill -9 $pid;done; xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}'); for pid in $xvfb_pids; do kill -9 $pid; done" EXIT

But this oblige me to press "CTRL+C" many times, on each run of subprocess from inside my script, something like:

Testing nsi.bd.helpcenter ...^C:  --  Total time: 0min 0seg
Testing nsi.bibliography ...^C:  --  Total time: 0min 0seg
Testing nsi.digitallibrary ...^C:  --  Total time: 0min 0seg
Testing nsi.digitallibraryinstaller ...^C:  --  Total time: 0min 1seg
Testing nsi.digitallibraryskins ...^C:  --  Total time: 0min 0seg
....#continues

Changing the final of the trap line from EXIT to SIGINT , like this:

trap "selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}');for pid in $selenium_pids; do kill -9 $pid;done; xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}'); for pid in $xvfb_pids; do kill -9 $pid; done" SIGINT

Makes the same thing.

What now to exit on the first CTRL+C?

Because I tried to add a "exit 1" to the final of the string , like trap "... ;exit 1"

It worked to exit on the first CTRL+C, but didn't killed the processes I wanted.

Ideas?

Was it helpful?

Solution

Got what I wanted with this code:

finalize_xvfb_and_selenium() {
    selenium_pids=$(ps ux | awk '/selenium/ && !/awk/ {print $2}')
    for pid in $selenium_pids; do 
        kill -9 $pid
    done 
    xvfb_pids=$(ps ux | awk '/Xvfb/ && !/awk/ {print $2}') 
    for pid in $xvfb_pids; do 
        kill -9 $pid
    done
}

finalize_xvfb_and_selenium_and_exit() {
    finalize_xvfb_and_selenium
    echo -e "\n\nXvfb and seleniumrc finalized. Exiting ..."
    exit 13
}

#trap (CTRL+C) signal, to finalize proccess running before exit
trap finalize_xvfb_and_selenium_and_exit SIGINT

I'm aware that there are better resources than using kill -9 everywhere.

OTHER TIPS

You want to trap signals.

When the user hits control-c at the terminal the OS issues a SIGINT to the current process. This signal can be trapped and handles. How you do that is a shell dependent issue and you should check your shells man page.

Note that some signals can not be trapped. Notably SIGKILL which is what kill -9 sends.


In light of the edit: bash can return the process ID of programs that you start. It would be possible to capture all them as you go so that you don't have to parse the output of ps. You might also consider sending you children some other signal (maybe SIGUSR1) having already set up a trap on that so that they will recursively kill their children.

All that said, your getting into deep shell magic territory. There are some books around which might help, but I don't know the titles off the top of my head.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top