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?
When you hit Ctrl + c , the line discipline of your terminal sends SIGINT to processes in the foreground process group. Bash, when job control is disabled, runs everything in the same process group as the bash process itself. Job control is disabled by default when Bash interprets a script.
To trap Ctrl-C in a shell script, we will need to use the trap shell builtin command. When a user sends a Ctrl-C interrupt signal, the signal SIGINT (Signal number 2) is sent.
While in a command line such as MS-DOS, Linux, and Unix, Ctrl + C is used to send a SIGINT signal, which cancels or terminates the currently-running program. For example, if a script or program is frozen or stuck in an infinite loop, pressing Ctrl + C cancels that command and returns you to the command line.
Ctrl+C sends a SIGINT
signal.
kill -INT <pid>
sends a SIGINT
signal too:
# Terminates the program (like Ctrl+C) kill -INT 888 # Force kill kill -9 888
Assuming 888
is your process ID.
Note that kill 888
sends a SIGTERM
signal, which is slightly different, but will also ask for the program to stop. So if you know what you are doing (no handler bound to SIGINT
in the program), a simple kill
is enough.
To get the PID of the last command launched in your script, use $!
:
# Launch script in background ./my_script.sh & # Get its PID PID=$! # Wait for 2 seconds sleep 2 # Kill it kill $PID
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 ===
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With