取消暂停不是从终端启动的进程

取消暂停不是从终端启动的进程

我在登录时从 init 脚本启动 emacs。有时我会不小心用ctrl+暂停它z,我不知道如何恢复。

如果我从终端开始,jobsfg可以解决问题,但在这种情况下没有终端可以运行。

我可以看到进程正在运行:

gauthier@sobel:~/data $ ps aux | grep emacs
gauthier  2932  0.0  0.6 565500 112540 ?       Sl   Apr14   0:11 emacs
gauthier 15189  0.0  0.0  11744   932 pts/2    S+   15:54   0:00 grep --color=auto emacs

答案1

你可以运行

kill -SIGCONT [pid]

或者

killall -SIGCONT [process name]

恢复具有指定 PID 或进程名称的进程。

答案2

Emacs 并没有真正被暂停。

正如我们在故障排除过程中发现的那样,emacs 并没有真正被暂停。T通过 查看时,暂停的进程会显示为其状态的一部分ps,而在您的情况下,emacs 显示S,这仅仅意味着它正在等待事件(在本例中,等待用户交互)。

如“进程状态代码”部分所述man ps

               S    interruptible sleep (waiting for an event to complete)
               T    stopped, either by a job control signal or because it is
                    being traced

当一个进程被挂起时,这被认为是一个作业控制信号,因为挂起进程主要是作为作业控制的一部分来完成的(在&命令的末尾,Ctrl+Z发出在终端以及jobsshell 内置命令)。 请参阅手册ps本身用于记录其他州的代码D,,,,,和。RWXZ

Emacs 被图标化了,并没有被暂停。当在终端中向前台进程发出Ctrl+时,它会导致进程暂停。但是您在 GUI emacs 窗口中按下了+ 。以这种方式给出+不会暂停程序——例如,在许多应用程序(如 Firefox 和 LibreOffice)中,+是ZCtrlZCtrlZCtrlZ撤消

作为你可以确认,当通过图形界面使用 emacs 时,Ctrl+Z是将窗口图标化(即最小化)或将其取消图标化(即恢复)(如果窗口已经图标化)的组合键。当然,您必须选择图标化的窗口才能Ctrl使用+将其图标化Z,但您的窗口管理器似乎不支持它。

请注意,当您在终端窗口中按下Ctrl+Z时,emacs 本身不太可能会拦截它并暂停自身。相反,在终端中发出的Ctrl+通常会暂停处理,而在 GUI 窗口中发出的+通常不会。ZCtrlZ

既然你说你“仍然有兴趣知道如何从终端取消暂停进程”,并且对如何知道某个进程是否真的被暂停(以及Ctrl+何时Z暂停和不暂停进程)的解释可以合理地介绍关于这个问题的答案,我决定用这个答案的剩余部分来解决这个问题的这一部分。

从不同的终端恢复暂停的进程

如果您有权访问暂停程序的控制终端,则jobsfgbg内置命令允许您查看和恢复该程序。如果您无权访问该程序的控制终端,而您需要做的只是恢复该进程但不在终端上给它输入,也不读取它的输出, 你可以发送进程 SIGCONT 详见 zhongfu 的回答。如果图形程序已暂停并且您无法从其控制终端恢复它,您可能会这样做。这是因为我们大多数时候与大多数 GUI 应用程序交互的主要方式是通过其图形 UI,而不是通过终端。

但是,如果你需要分离进程的标准流从其原始终端并将它们重新连接到不同的终端 - 即恢复暂停的进程并在与启动它不同的终端中与其交互 - 这并不是那么简单。

  • 如果它是一个命令行程序,旨在主要通过终端而不是通过 GUI 或本地 Web 服务器等其他机制与用户交互,那么您主要需要这样做。例如,emacs -nw与 GUI 相比,您更有可能需要这样做emacs

如果你提前计划好了,可以将进程重新连接到不同的终端

如果您在运行程序时预见到了这种需要,则可以通过在终端复用器而不是普通的终端。screentmux这样做;参见man screenman tmux了解详情。 (也可以看看byobu) 在终端多路复用器中启动的进程并不直接连接到您与其交互的终端,而是连接到多路复用器提供的伪终端。

  • 例如,您可以screen emacs在一个终端中运行,然后通过按Ctrl+A再按Ctrl+将其从该终端分离D,然后通过运行 在另一个终端(或同一个终端)上打开它screen -r。或者,如果您从未将其从第一个终端分离,则可以将其从那里分离,然后使用 将其重新连接到当前终端screen -rd

如果你没有提前计划,请将进程重新连接到不同的终端

如果您没有在终端多路复用器中启动您的程序,而需要将其与原始程序分离并附加到新的程序,这通常是可能的,尽管对于默认情况下在 Ubuntu 中安装的实用程序来说这并不简单。可以通过在调试器中打开和操作该过程来完成。

幸运的是,已经有人编写了实用程序,可以轻松实现这一点——或者至少尝试很容易。我建议雷普特。 (也可以看看注入代码内尔克,以及 reptyr 页面上三者的比较。)Reptyr 的自述文件reptyr github 页面提供使用信息。在 Ubuntu 上,要下载并构建 reptyr、运行其测试套件并安装它,您可以使用以下命令:

# Install build dependencies and set up /usr/local/src for administrators.
sudo apt-get update && sudo apt-get install build-essential git python-pip
pip install pexpect
cd /usr/local/src && sudo chgrp sudo . && sudo chmod g+w,+t .

# Retrieve, configure, build, test, and install reptyr.
git clone https://github.com/nelhage/reptyr.git && cd reptyr
make && sudo make test install

您可能注意到,我test使用 sudo 将目标设置为 root。通常的最佳做法是作为普通用户构建和测试软件,然后提升为 root 以进行安装。但是,在 Ubuntu 的默认配置中,非 root 用户运行时 reptyr 不起作用。这是因为 reptyr 通过将进程作为调试器附加到进程来操纵进程的文件描述符,但作为一项安全功能,禁止非 root 进程调试非其后代的进程

当您实际使用该reptyr命令时,您不会使用 来运行它sudo。相反,您需要以拥有该进程的同一用户的身份从属于该用户的终端运行 reptyr。(可能有一种方法可以在不这样做的情况下使其工作,但这种方法只对我有用。)

reptyr在 Ubuntu 上使用

允许进程调试同一用户拥有的非后代进程只有在正在运行的程序被成功利用(或者您有恶意软件)时才可能导致问题。允许 reptyr 工作同时保持相对较低的安全风险的一种方法是仅在需要运行 reptyr 时才允许它(这种情况可能很少发生,但愿如此),然后重新禁用它。

因此,假设您已经启动了一个非图形 Emacs 实例(在无法访问的终端中):

emacs -nw

这可能会或可能不会被暂停。从另一个终端,将ptrace_scope1 更改为 0,以允许进程调试非其后代的进程:

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

然后运行reptyr,将进程的 PID 作为参数传递,尝试将其与旧终端分离并将其附加到新终端:

reptyr PID

ps x您可以在或的输出中找到 PIDpgrep或者pidof如果只有一个emacs正在运行,您可以找到 PID 并将其传递给reptyr单个命令:

reptyr $(pidof emacs)

我发现这通常有时可以工作,但有时不行。如果reptyr根本没有输出,则可能必须按Ctrl+Z才能使用该程序。(我不知道为什么会这样,但运行时显示,在这种特定情况下,当我按+时,ps没有任何内容被暂停或取消暂停,因此我怀疑这与 reptyr 和我的 shell 的作业控制功能之间的交互有关。)CtrlZ

在重新附加的过程中,作业控制可能无法完全发挥作用;例如,您可能无法始终使用Ctrl+来暂停它Z

使用完 reptyr 后,ptrace_scope为了安全起见,您可以将其设置回 1:

echo 1 | sudo tee /proc/sys/kernel/yama/ptrace_scope

提前规划更容易、更可靠尽可能。如果您启动交互式程序的终端可能无法访问,最好使用终端多路复用器,如screentmux(如上所述)。

相关内容