views:

55

answers:

2

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?

+2  A: 

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.

dmckee
This is correct, but showing how to do it might make it a better answer
Daenyth
@dmckee @Daenyth please see my edit
Gabriel L. Oliveira
@dmckee Thank you, I'll try to continue look for that.
Gabriel L. Oliveira
@dmckee @Daenyth Just out of curiosity, I answered the question. Maybe you want to look. Thank you for help.
Gabriel L. Oliveira
@Gabriel: The culture around here accepts (and to some extent expects) putting self answer in an answer so that we can vote on them. And that's to you advantage in the sense that answer votes are worth more than question votes and you could get one of each for a single person.
dmckee
@dmckee Did that. Thank you for the lesson.
Gabriel L. Oliveira
+1  A: 

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

Although I'm aware that there are better resources than using "kill -9" everywhere, and I'll study them to improve the code.
Thanks everyone that helped me find this result.

Gabriel L. Oliveira