Linux下如何启动一个处于挂起状态的进程?

jav*_*top 21 linux process background-process

实际上,我需要一个行为正常的进程,就好像我Ctrl+Z在它开始后就按下了一样。

希望可以使用 shell 脚本来做这样的事情。

(另外,知道结果 PID 会很棒,所以我可以在之后继续这个过程。)

Mik*_*eyB 27

您在哪个环境中创建流程?

如果您是在 C 代码等环境中执行此操作,则可以 fork() 然后在子进程中,在 exec() 之前向自己发送一个 SIGSTOP,以防止进一步执行。

一个更通用的解决方案(可能是最好的)是创建一个这样做的存根。所以存根程序将:

  • 获取由真实程序的名称和参数组成的参数
  • 向自身发送 SIGSTOP
  • exec() 带有适当参数的真实程序

这将确保您在向其发送信号之前避免任何与新处理相关的竞争条件。


外壳示例:

#!/bin/bash
kill -STOP $$
exec "$@"
Run Code Online (Sandbox Code Playgroud)

并使用上面的代码:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 
Run Code Online (Sandbox Code Playgroud)

jobs -l示出了PID。但是,如果您是从 shell 执行此操作,则不需要直接使用 PID。你可以这样做:(kill -CONT %1假设你只有一份工作)。

做不止一份工作?留给读者练习:)


小智 20

MikeyB 的回答是正确的。从这个关于超级用户的问题,这里有一个更简洁的版本:

( kill -SIGSTOP $BASHPID; exec my_command ) &
Run Code Online (Sandbox Code Playgroud)

要理解这一点,需要了解进程是如何在 unix 上启动的:exec系统调用将当前运行的程序替换为一个新程序,同时保留现有的 PID。所以创建独立进程的方式是先fork,然后exec将子进程中正在运行的程序替换为所需的程序。

这个 shell 命令的组成部分是:

  1. 括号(...)开始一个子 shell:另一个 BASH 实例。
  2. kill命令向该进程发送 STOP 信号,使其进入挂起状态。
  3. 一旦您允许进程继续(通过向其发送CONT信号),该exec命令就会使其自身替换为您想要的程序。 my_command保留子shell的原始PID。
  4. 您可以使用该$!变量来获取进程的 PID。

  • 我喜欢这个,因为它从根本上是正确的(只是我必须使用 `-s STOP` 而不是 `-SIGSTOP`)。仍然想知道:为什么它必须是 `$BASHPID` 而不是 `$$`?(我可能不太明白其中的区别)。 (2认同)

小智 7

启动进程后,您可以向它发送 SIGSTOP 以暂停它。要恢复它,请发送 SIGCONT。我认为这个小脚本可以帮助你

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID
Run Code Online (Sandbox Code Playgroud)

它运行进程(命令作为参数发送),挂起它,打印进程 id 并等待它结束。

  • 比赛的另一天。 (19认同)
  • 正如您所知,子进程可能在您有机会向其发送 STOP 信号之前就完成了。 (8认同)