如何从 bash 脚本发送控件 + c?

我将在 bash 脚本中启动许多屏幕,然后在每个屏幕中运行 django 的 runserver命令。我希望能够以编程方式停止他们所有以及,这需要我发送 Control+crunserver

如何从 bash 脚本发送这些击键?

175069 次浏览

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
===

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.

    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.

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 <pid> 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: