我正在学习Linux。想到了可以将进程附加到终端的想法。将进程附加到终端 (TTY) 意味着什么?我为什么要这样做?
答案1
笔记: 为了更好地了解 Unix 中的作业控制,我将引导您访问有关该主题的 Wikipedia 页面 -作业控制(Unix)。
附加终端?
“附加到终端”这个短语通常是您在 shell 上下文中谈论作业时会听到的。但它确实还有其他含义。短语“将进程附加到终端”还可以表示使用诸如gdb
或strace
之类的工具lsof
附加到特定进程 ID (PID) 并列出信息或监视它。
我将讨论这两个问题,但首先,我将讨论作业队列,因为我怀疑这就是您正在寻找的队列。
背景 - 作业队列
在类 Unix 操作系统中,您通常会看到作业的概念。在我使用过的大多数类 Unix 操作系统中,它们通常都以类似的方式工作。也就是说,它们可以在后台运行并在队列(作业队列)中分配一个编号,并且可以根据该作业队列中它们的编号的上下文对它们进行操作。
为了将某些内容放入作业队列,他们通常将此行为称为后台处理。当您恢复已在后台运行的作业时,您将其称为前台处理。通常执行此操作的命令bg
是fg
。您还可以使用&
运行的任何命令末尾的“&”符号立即将作业放入后台。
例子
工作
$ sleep 2 &
[1] 19189
在这里,我运行 sleep 命令 2 秒钟并将其置于后台。输出立即为您提供有用的信息,例如作业队列号 ( [1]
) 和后台作业的进程 ID 19189。
当此作业最终终止时,它将在运行的终端中打印此类消息:
$
[1]+ Done sleep 2
前景和背景
要对已后台化的作业执行操作:
$ sleep 20 &
[1] 19207
$ fg
sleep 20
^C
在这里,我将一个作业发送到后台 ( &
),然后将其带回前台 ( fg
),然后使用Ctrl+ C( ^C
) 命令终止它。
如果我们有多个后台作业:
$ sleep 20 &
[1] 19224
$ sleep 20 &
[2] 19225
$ sleep 20 &
[3] 19226
$ jobs
[1] Running sleep 20 &
[2]- Running sleep 20 &
[3]+ Running sleep 20 &
我们可以用命令看到它们jobs
。注意#3 和 #2 旁边的小+
和。-
如果我运行该fg
命令而不指定作业队列编号,我将获得放入作业队列的最后一个作业 ( +
)。例如:
$ fg
sleep 20
^C
$ jobs
[1]- Running sleep 20 &
[2]+ Running sleep 20 &
杀戮
您可以使用作业队列编号来处理作业。其中一种方法就是杀死它们。要引用作业队列的编号,%
当您想用其他命令(例如 )引用它们时,可以在它们前面加上 前缀kill
。当然,您可以kill
一次全部使用多个,也可以只使用一个:
$ kill %3 %4 %5
$ jobs
[3] Terminated sleep 20
[4] Terminated sleep 20
[5]- Terminated sleep 20
[6]+ Running sleep 20 &
后台附加到 PID
将进程附加到终端也可能意味着以下内容。这是我的 shell 的 PID:
$ echo $$
23543
在另一个 shell 中,我正在运行strace
并连接到该进程,以查看它正在执行哪些系统调用:
$ strace -p 23543
strace: Process 23543 attached
read(0,
笔记:在这里您可以看到它正在等待read
for 命令。这就是终端/shell 的作用。
在这里我们可以看到我已经开始在其中键入命令ls
,并且 shell 正在以系统调用的形式将这个回显回显到 shell write()
。
read(0, "l", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "l", 1) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "s", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "s", 1) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0,
这是将进程附加到终端的另一种形式。
其他形式
这里也可以假设将进程附加到终端的更模糊的参考之一。本 U&L 问答题为:如何将终端附加到分离的进程?涵盖了该内容的所有形式。
这种形式的引用的基本前提是,您已经完成了后台作业,并将其与当前 shell“断开”。您可以使用命令nohup
或 来执行此操作disown
。
一旦进程被否认,您就不能再使用jobs
、fg
或bg
命令对其进行操作。它不再与您当前 shell 的 PID 相关联。
重新获取以前否认的进程的传统方法是使用诸如 之类的工具reptyr
,它将重新将 PID 附加到现有的 shell。例如,假设我们开始了 2 份工作,nohup
他们:
$ nohup sleep 200 &
[1] 19720
$ nohup sleep 200 &
[2] 19721
仍然附加到我们终端的作业队列,让disown
他们:
$ jobs
[1]- Running nohup sleep 200 &
[2]+ Running nohup sleep 200 &
$ disown -a
现在他们走了:
$ jobs
$
它们仍然被列为我们原始 shell 的 PID (23543) 的子级:
$ ps -eaf|grep -E "19720|19721"
vagrant 19720 23543 0 18:29 pts/1 00:00:00 sleep 200
vagrant 19721 23543 0 18:29 pts/1 00:00:00 sleep 200
现在,如果我们退出并重新登录,我们将看到这些进程现在被列为主 PID 1 的父进程:
$ ps -eaf|grep -E "19720|19721"
vagrant 19720 1 0 18:29 ? 00:00:00 sleep 200
vagrant 19721 1 0 18:29 ? 00:00:00 sleep 200
这些流程之所以能够做到这一点,是因为我们nohup
对它们进行了编辑和disown
编辑。让我们重新连接其中一个:
$ reptyr -s 19720
[-] Timed out waiting for child stop.
^C
笔记:在上面,我将 PID 19720 重新附加到我的 shell,然后通过Ctrl+杀死它C。我们可以看到它现在已经消失了:
$ ps -eaf|grep -E "19720|19721"
vagrant 19721 1 0 18:29 ? 00:00:00 sleep 200