5

I am trying to handle ctrl+c in a shell script. I have code running in a while loop but I am calling the binary from a shell script and running it in the background so when I want to stop the binary it should stop. Code is below of hello.c

#include <stdio.h>
    
int main()
{
    while(1)
    {
        int n1,n2;
        printf("Enter the first number\n");
        scanf("%d",&n1);
        printf("Enter the second number\n");
        scanf("%d",&n2);
        printf("Entered number are n1 = %d , n2 =%d\n",n1,n2);
    }
}

Below is the bash script which I use.

#/i/bin/sh
echo run the hello binary
./hello < in.txt &

trap_ctrlc()
{
    ps -eaf | grep hello | grep -v grep | awk  '{print $2}' | xargs kill -9
    echo trap_ctrlc
    exit
}

trap trap_ctrlc SIGHUP SIGINT SIGTERM

After starting the script the hello binary is running continuously. I have killed this binary from other terminal using kill -9 pid command.

I have tried the trap_ctrlc function but it does not work. How to handle ctrl+c in a shell script?

In in.txt I have added the input so I can pass this file directly to the binary.

1
2

Output:

Enter the first number  
Enter the second number  
Entered number are n1 = 1 , n2 =2  
Enter the first number    
Enter the second number  
Entered number are n1 = 1 , n2 =2   
Enter the first number    
Enter the second number    
Entered number are n1 = 1 , n2 =2  

And it going continuously.

codersl
  • 2,222
  • 4
  • 30
  • 33
Sagar Talole
  • 51
  • 1
  • 3
  • @TedLyngmo Thank you so much this works. I have one doubt if i ran say 2 or 3 binary in script then how to kill all binaries after hitting ctrl +c. And about the solution on script on line number 4 i am getting the error "Syntax error: "(" unexpected" The 'function' written before print_forever caused this issue. So i removed it. – Sagar Talole Oct 05 '20 at 10:32
  • `kill -9` is SIGKILL, you can't trap SIGKILL. See: https://man7.org/linux/man-pages/man7/signal.7.html You could try `kill -HUP` and just plain `kill`. – Kingsley Mar 17 '22 at 21:47

1 Answers1

5

Change your program so it checks if reading data actually succeeded:

#include <stdio.h>

int main()
{
    int n1,n2;
    while(1) {
        printf("Enter the first number\n");
        if(scanf("%d",&n1) != 1) return 0;   /* check here */
        printf("Enter the second number\n");
        if(scanf("%d",&n2) != 1) return 0;   /* check here */
        printf("Entered number are n1 = %d , n2 =%d\n",n1,n2);
    }
}

It will now terminate when the input from in.txt is depleted.

To make something that reads from in.txt many times, you could create a loop in your script that feeds ./hello forever (or until it's killed).

Example:

#!/bin/bash

# a function to repeatedly print the content in "in.txt"
function print_forever() {
    while [ 1 ];
    do
        cat "$1"
        sleep 1
    done
}

echo run the hello binary
print_forever in.txt | ./hello &
pid=$!
echo "background process $pid started"

trap_ctrlc() {
    kill $pid
    echo -e "\nkill=$? (0 = success)\n"
    wait $pid
    echo "wait=$? (the exit status from the background process)"
    echo -e "\n\ntrap_ctrlc\n\n"
}

trap trap_ctrlc INT

# wait for all background processes to terminate
wait

Possible output:

$ ./hello.sh
run the hello binary
background process 262717 started
Enter the first number
Enter the second number
Entered number are n1 = 1 , n2 =2
Enter the first number
Enter the second number
Entered number are n1 = 1 , n2 =2
Enter the first number
^C
kill=0 (0 = success)

wait=143 (the exit status from the background process)


trap_ctrlc

Another option can be to kill the child after the wait is interrupted:

#!/bin/bash

function print_forever() {
    while [ 1 ];
    do
        cat "$1"
        sleep 1
    done
}
 
echo run the hello binary
print_forever in.txt | ./hello &
pid=$!
echo "background process $pid started"
 
trap_ctrlc() {
    echo -e "\n\ntrap_ctrlc\n\n"
}
 
trap trap_ctrlc INT
 
# wait for all background processes to terminate
wait
echo first wait=$?
kill $pid
echo -e "\nkill=$? (0 = success)\n"
wait $pid
echo "wait=$? (the exit status from the background process)"`
``
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • the hello binary is killed but hello.sh script is still running. After hitting the Ctrl+c not able to come out from the script. Enter the first number Enter the second number Entered number are n1 = 1 , n2 =2 Enter the first number ^C-e kill=0 (0 = success) ^Cnew.sh: 20: kill: No such process -e kill=1 (0 = success) ^Cnew.sh: 20: kill: No such process And still it going on so i grep the script and killed it from different terminal – Sagar Talole Oct 05 '20 at 12:01
  • @SagarTalole Is that the result when you run the exact [tag:c] program and [tag:bash] script in the answer or is there any difference? – Ted Lyngmo Oct 05 '20 at 12:27
  • No difference. I copied the code your shared and checked. – Sagar Talole Oct 08 '20 at 11:41
  • @SagarTalole That's odd. What if you try a different approach, like [this](https://pastebin.com/rynx9GgC)? Can you create a paste of the output if you run that script and press ctrl-c? – Ted Lyngmo Oct 08 '20 at 11:47
  • I am not able to open the link you provided due to security reason. – Sagar Talole Oct 09 '20 at 14:50
  • @SagarTalole Ok, I added it in the answer as an alternative. If this doesn't exit the script there's something wierd going on (like restarting the `wait` call that _should be_ interrupted by the signal). – Ted Lyngmo Oct 09 '20 at 16:41
  • Can you provide the output you get from running the alternative script? Use whatever pastebin-like service you can use. – Ted Lyngmo Oct 09 '20 at 19:08
  • @SagarTalole This annoys me as well, so I'd like to find out where my answer doesn't hold. In a Posix environment, I'm pretty sure it should work. – Ted Lyngmo Oct 10 '20 at 01:08
  • What does `trap trap_ctrlc INT` do in your last version? Thank you. – d-b Jun 11 '23 at 06:29
  • @d-b Here's a quick intro: https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html – Ted Lyngmo Jun 11 '23 at 06:41