如何从bash脚本发送control + c?

ghi*_*man 57 bash gnu-screen

我在bash脚本中启动了一些屏幕,然后runserver在每个屏幕中运行django的命令.我希望能够以编程方式阻止它们,这需要我发送Control+crunserver.

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

Mat*_*oli 74

Ctrl+C发送SIGINT信号.

kill -INT <pid>发送SIGINT信号:

# Terminates the program (like Ctrl+C)
kill -INT 888
# Force kill
kill -9 888
Run Code Online (Sandbox Code Playgroud)

假设888是您的进程ID.


请注意,kill 888发送SIGTERM信号略有不同,但也会要求程序停止.所以,如果你知道自己在做什么(程序中没有处理SIGINT程序),那么简单kill就足够了.

要获取脚本中启动的最后一个命令的PID,请使用$!:

# Launch script in background
./my_script.sh &
# Get its PID
PID=$!
# Wait for 2 seconds
sleep 2
# Kill it
kill $PID
Run Code Online (Sandbox Code Playgroud)

  • Per [`man kill`](http://linux.die.net/man/1/kill):_如果没有指定信号,则TERM信号为sent_,因此`kill $ PID`不发送`SIGINT`给这个过程,因此与Ctrl + C键盘事件不一样 (3认同)
  • ⚠️`ctrl`+`c` 与 `kill -SIGINT &lt;pid&gt;` 不完全相同。前者向组发送“INT”信号,后者仅向给定的“&lt;pid&gt;”发送信号。[参见这个问题](/sf/answers/588448941/)。 (3认同)

pax*_*blo 12

CTRL-C 通常会向进程发送SIGINT信号,因此您可以执行以下操作:

kill -INT <processID>
Run Code Online (Sandbox Code Playgroud)

从命令行(或脚本),来影响具体processID.

我说"通常"是因为,与大多数UNIX一样,这几乎是无限可配置的.如果执行stty -a,您可以看到哪个键序列与intr信号相关联.这可能是,CTRL-C但键序列可能完全映射到其他东西.


下面的脚本说明这个动作(尽管TERM不是INT因为sleep没有反应INT在我的环境):

#!/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 ===
Run Code Online (Sandbox Code Playgroud)

它基本上启动了一个小时日志sleep过程并获取其进程ID.然后在杀死进程之前输出相关的进程详细信息.

经过一小段时间后,它会检查进程表以查看进程是否已经消失.正如您从脚本输出中看到的那样,它确实消失了:

===
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
===
Run Code Online (Sandbox Code Playgroud)


Uly*_* BN 6

ctrl+ckill -INT <pid>不完全一样

要模拟ctrl+c我们首先需要了解差异。

kill -INT <pid>INT信号发送到给定的进程(通过它找到pid)。

ctrl+c映射为intr特殊字符,当终端接收到该特殊字符时,该字符应发送INT到该终端的前台进程组。您可以通过针对给定<pid>. 这可以通过-在 kill 命令中的信号前加上 a 来完成。因此你想要的命令是:

kill -INT -<pid>
Run Code Online (Sandbox Code Playgroud)

您可以使用脚本轻松测试它:

#!/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
Run Code Online (Sandbox Code Playgroud)

资料来源:

  • pid 前面的`-` 救了我们一命!其他的都没有用!谢谢你! (2认同)