Sagar Talole
Sagar Talole

Reputation: 51

How to handle ctrl+c in a shell script?

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.

Upvotes: 5

Views: 11820

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 118077

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)"`
``

Upvotes: 6

Related Questions