[bash] How to send control+c from a bash script?

I'm starting a number of screens in a bash script, then running django's runserver command in each of them. I'd like to be able to programmatically stop them all as well, which requires me to send Control+c to runserver.

How can I send these keystrokes from my bash script?

This question is related to bash gnu-screen

The answer is


ctrl+c and kill -INT <pid> are not exactly the same, to emulate ctrl+c we need to first understand the difference.

kill -INT <pid> will send the INT signal to a given process (found with its pid).

ctrl+c is mapped to the intr special character which when received by the terminal should send INT to the foreground process group of that terminal. You can emulate that by targetting the group of your given <pid>. It can be done by prepending a - before the signal in the kill command. Hence the command you want is:

kill -INT -<pid>

You can test it pretty easily with a script:

#!/usr/bin/env ruby

fork {
    trap(:INT) {
        puts 'signal received in child!'
        exit
    }
    sleep 1_000
}

puts "run `kill -INT -#{Process.pid}` in any other terminal window."
Process.wait

Sources:


    pgrep -f process_name > any_file_name
    sed -i 's/^/kill /' any_file_name
    chmod 777 any_file_name
    ./any_file_name

for example 'pgrep -f firefox' will grep the PID of running 'firefox' and will save this PID to a file called 'any_file_name'. 'sed' command will add the 'kill' in the beginning of the PID number in 'any_file_name' file. Third line will make 'any_file_name' file executable. Now forth line will kill the PID available in the file 'any_file_name'. Writing the above four lines in a file and executing that file can do the control-C. Working absolutely fine for me.


You can get the PID of a particular process like MySQL by using following commands: ps -e | pgrep mysql

This command will give you the PID of MySQL rocess. e.g, 13954 Now, type following command on terminal. kill -9 13954 This will kill the process of MySQL.


CTRL-C generally sends a SIGINT signal to the process so you can simply do:

kill -INT <processID>

from the command line (or a script), to affect the specific processID.

I say "generally" because, as with most of UNIX, this is near infinitely configurable. If you execute stty -a, you can see which key sequence is tied to the intr signal. This will probably be CTRL-C but that key sequence may be mapped to something else entirely.


The following script shows this in action (albeit with TERM rather than INT since sleep doesn't react to INT in my environment):

#!/usr/bin/env bash

sleep 3600 &
pid=$!
sleep 5

echo ===
echo PID is $pid, before kill:
ps -ef | grep -E "PPID|$pid" | sed 's/^/   /'
echo ===

( kill -TERM $pid ) 2>&1
sleep 5

echo ===
echo PID is $pid, after kill:
ps -ef | grep -E "PPID|$pid" | sed 's/^/   /'
echo ===

It basically starts an hour-log sleep process and grabs its process ID. It then outputs the relevant process details before killing the process.

After a small wait, it then checks the process table to see if the process has gone. As you can see from the output of the script, it is indeed gone:

===
PID is 28380, before kill:
   UID   PID     PPID    TTY     STIME      COMMAND
   pax   28380   24652   tty42   09:26:49   /bin/sleep
===
./qq.sh: line 12: 28380 Terminated              sleep 3600
===
PID is 28380, after kill:
   UID   PID     PPID    TTY     STIME      COMMAND
===