【问题标题】:What happens in BASH when you do Ctrl-C (hint, it's not simply sending a SIGINT)当您执行 Ctrl-C 时 BASH 中会发生什么(提示,它不仅仅是发送一个 SIGINT)
【发布时间】:2011-10-01 06:19:40
【问题描述】:

先了解一点背景 - 当我从公司 Internet 下载 apt-get install 时,它会在前 10 秒左右提供高速爆发 (400-500KB/s),然后下降到该速度的十分之一 (40 -50KB/s),然后几分钟后就真的很惨了(4-5KB/s)。这让我觉得系统管理员已经实施了某种网络节流方案。

现在我知道网络不仅仅是不稳定的,因为如果我在 10 秒后启动 apt-get install fooCtrl-C 并立即再次运行 apt-get install foo(通过向上箭头并输入使用 bash 历史记录) ,然后重复这个过程几分钟,直到所有包都下载完毕,我可以非常快地下载大包。特别是,即使在使用 Ctrl-C 中止下载后,apt-get 似乎也能够在下一次调用中恢复下载。

当然,盯着屏幕每 10 秒按一次 Ctrl-C Up Enter 真的很无聊,所以我写了一个 shell 脚本 -

#!/bin/sh
for i in `seq 1 100` ; do
    sudo apt-get install foo -y &
    sleep 10
    sudo kill -2 $!
done

这似乎有效。它生成 apt-get,运行 10 秒,然后杀死(通过发送 SIGINT)并再次启动它。但是,它并没有真正起作用,因为现在 apt-get 不会在后续调用中恢复下载!

我从一个终端运行sudo apt-get install foo 然后从另一个终端运行kill -2 <PID of apt-get> 的一个实验。即使在这种情况下,当我重新启动 apt-get 时,它也不会恢复下载。

很明显,Ctrl-C 等同于 SIGINT。当我手动执行 Ctrl-C 时,还会发生其他事情,这让 apt-get 有机会保存下载状态。问题是 - 它是什么?

编辑

这些是我目前收到的建议,但没有雪茄。谜底加深! -

  1. sudo kill -2 $! 上,信号可能会转到sudo 而不是apt-get。这不是原因,因为如上所述,我还尝试将 SIGINT 专门发送到 apt-get 的 PID,甚至阻止了 apt-get 保存其状态。

  2. Sudo 捕获信号并将其他一些信号发送到 apt-get。我尝试发送 apt-get 所有我能想到的信号!它仍然不会恢复其中任何一个的下载。只有当我按 Ctrl-C 杀死它时,它才会恢复下载。

  3. 如果 SIGINT 来自脚本而不是交互式 shell,则 Apt-get 处理 SIGINT 的方式不同。再一次,上面的“实验”证明这不是真的。

【问题讨论】:

  • 有人可能会推测apt-get 安装了一个SIGINT 处理程序,该处理程序只是根据它是否是运行在其上的交互式外壳来不同地处理其信号......
  • 嗯,不能只是这样,因为在一个 shell 中运行 apt-get 并从另一个 shell 中杀死它仍然应该允许它捕获 SIGINT 并执行保存下载状态所需的任何操作。

标签: bash process kill apt sigint


【解决方案1】:

提示,它不仅仅是发送一个 信号)。

是的,它只是发送SIGINT :-) 节流是正在发生的事情,你说得对。这是我怀疑正在发生的事情:

  • 有些东西限制了连接的带宽。为了跟踪连接,它还包括其他参数中的源端口(这是一个坏主意 IMO)

  • 当你杀死apt-get并重新启动它时,它自然会得到一个新的TCP源端口和邪恶实体节流你会想,“哦,这是一个新的连接 em>”,其实是这样的

那么你如何加快速度呢?那么真正的解决方案是使用多个并行下载。我自己从未使用过它,但我听说过一个名为“apt-fast”(实际上是一个 bash 脚本本身)的工具,它可以做这样的事情。

编辑

再次阅读问题后,我怀疑信号未发送至apt-get

sudo apt-get install foo -y &
sudo kill -2 $! # sends signal to sudo, which sends whatever it wants to `apt-get`

所以我相信sudo 会捕捉到信号并将其他内容(sigterm?sighup?)发送到apt-get

【讨论】:

  • 那么为什么在按向上箭头并进入使用bash历史记录时会继续下载?
  • @Thaddee Tyl 因为它正在启动一个新进程,选择一个新的源端口,新的 TCP 连接,新的“节流”开始时间。再次阅读我的答案:-)
  • 我的意思是,apt-get 是否会在某处存储它下载的内容的缓存?它通常会恢复下载吗?我不知道,我不经常使用它。我想知道为什么从其他终端启动时它也不会恢复下载。
  • @Thaddee Tyl 我不知道apt-get 是如何恢复下载的(老实说,我也不在乎),但我怀疑新的 TCP 连接是造成这一切的原因。跨度>
  • 嗯,问题不在于节流是如何工作的(我真的不在乎),而是Ctrl-Ckill -2 pid 之间的区别。
【解决方案2】:

好吧,正如cnicutar所说,它只是发送一个SIGINT。 现在,要说的关键在这里:

我怀疑信号没有发送到 apt-get

这是真的。让我解释一下。

运行sudo foo 启动一个sudo 进程,然后(即在您插入密码之后)调用foo;这是论点。一旦sudo 接受密码并调用foo,您就进入了foo 的“空格”。无论您在等待foo 完成时所做的一切都是在foo 而不是sudo 上完成的。

因此,在等待 apt 完成其工作时发送 CtrlC,该信号将发送到 apt

现在,如果您启动sudo,它的pid 存储在$! var 中。向该 pid/var 发送 kill 信号是向 sudo 发送 kill 信号,而不是后来由 sudo 启动的 apt。如果您想向apt 发送kill 信号,您可能需要使用pidof 实用程序。

自己测试:

sudo do-something
echo $!
pidof do-something

输出应该是两个不同的 pid
我希望这会有所帮助。

【讨论】:

  • 您所说的可能是一个因素。这就是为什么我做了我的问题中提到的“实验”。即使我得到了 apt-get(不是 sudo)的 PI​​D 并从另一个终端杀死它,它仍然会阻止 apt-get 保存状态。显然还有其他事情正在发生。
【解决方案3】:

好吧,谜团解开了!感谢Indian Linux Users Group 的乐于助人的人们。

这里的答案有两个——

首先,apt-get 调用另一个名为http 的程序来下载数据。

[~] ➔ file /usr/lib/apt/methods/http

/usr/lib/apt/methods/http: ELF 32-bit LSB executable, Intel 80386, version 1
(SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15,
stripped

请注意,这是一个可执行文件,甚至不是脚本,可能是为了在 perl/python/ruby 等尚不可用时支持在系统安装期间下载文件。

其次,当您在运行 apt-get 后按 Ctrl-C 时,SIGINT 将被发送到 http,而不是 apt-get。当http收到SIGINT时,会保存关机前的下载状态。

这是完美运行的更新脚本 -

#!/bin/sh
for i in `seq 1 100` ; do
    sudo apt-get install foo -y &
    sleep 10
    sudo kill -2 `ps -ae | grep " http" | awk '{print $1}'`
done

【讨论】:

    猜你喜欢
    • 2014-08-17
    • 2018-02-10
    • 2017-08-19
    • 2018-07-15
    • 1970-01-01
    • 2018-10-21
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    相关资源
    最近更新 更多