3

How do you kill a running process in a bash script without killing the script?

Goal

So... I need to kill a running process to continue with the execution of my script.

Here´s a stripped down version of my script:

# Setup
echo "Use ctrl+C to stop gathering data..."
./logger
#------------------
echo "Rest..."

I need to be able to kill ./logger without killing my script

Expected vs Actual Results

I was expecting a result like this:

Use ctrl+C to stop gathering data...
^C
Rest...

but it stops when I kill the program

use ctrl+C to stop gathering data...
^C

The ./logger command is a C program that already handles the SIGINT signal (Ctrl + C) but it won't stop until it receives it. Is there a way to stop the program without killing my script?

The C Program is not important but it looks something like this

#include <stdio.h>
#include <signal.h>

int flag = 1;

void handler(int i)
{
     flag = 0;
}

int main(int argc, char** argv)
{
    signal(SIGINT, handler);
    while(flag)
    {
       usleep(10000);
    }
}

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
VictorJimenez99
  • 323
  • 2
  • 9
  • You should use `sigaction` instead of `signal` as the latter is deprecated. – Daniel Walker Oct 03 '20 at 02:35
  • @TedLyngmo i dont know what you mean but im only running one command at a time in my script. – VictorJimenez99 Oct 03 '20 at 02:35
  • Why do you have parentheses around the `./logger` line? Is there a reason you need it to run in a subshell? – Daniel Walker Oct 03 '20 at 02:40
  • More important question: Have you set the `-e` flag at the top of your script? – Daniel Walker Oct 03 '20 at 02:46
  • @DanielWalker sorry im new to scripting in shell, but the whole command was this one. `$(\time -o $LOG -a -f 'Total Time Gathering Data: %E\n' ./freq_logger $DIR >> $LOG)` – VictorJimenez99 Oct 03 '20 at 02:46
  • 1
    Try stripping the bash script down to its essentials. For starters, have a script that just runs your C program and then put a simple command like `echo Check` on the next line. See if that works. What you need is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Daniel Walker Oct 03 '20 at 02:51

1 Answers1

4

If you type control-C at the terminal where the script is running, the signal goes to all the processes — the logger program and the script. And the script terminates because you've not told it to ignore signals while the logger is run. You can do that using the trap command but you'll need to undo the trapping before running the C program. See the Bash manual on Signals too.

For example, I have a program dribbler that generates messages, one every second by default, but it is configurable. I'm using it as a surrogate for your ./logger program. The -m options specifies the message; the -n option requests that the messages are numbered, and the -t option specifies output to standard output (instead of a file which it writes to by default).

#!/bin/bash
#
# SO 6418-0134

program="dribbler -t -n -m Hello"
echo "About to run '$program' command"

trap "" 2
(trap 2; $program)

echo "Continuing after '$program' exits"
sleep 1
echo "But not for long"

The sub-shell is necessary. When I run that script (trapper.sh), I get, for example:

$ bash trapper.sh
About to run 'dribbler -t -n -m Hello' command
0: Hello
1: Hello
2: Hello
3: Hello
^CContinuing after 'dribbler -t -n -m Hello' exits
But not for long
$

Incidentally, POSIX defines a command logger that writes messages using the syslog() function(s) to the syslog daemon.

It might also be worth reviewing the Q&A about Sending SIGINT to forked exec process which runs a script does not kill it, especially the accepted answer and its links to Q&A on other Stack Exchange sites, as it matters that you and I both executed a C program, not a shell script.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278