附加终端?

附加终端?

我正在学习Linux。想到了可以将进程附加到终端的想法。将进程附加到终端 (TTY) 意味着什么?我为什么要这样做?

答案1

笔记: 为了更好地了解 Unix 中的作业控制,我将引导您访问有关该主题的 Wikipedia 页面 -作业控制(Unix)


附加终端?

“附加到终端”这个短语通常是您在 shell 上下文中谈论作业时会听到的。但它确实还有其他含义。短语“将进程附加到终端”还可以表示使用诸如gdbstrace之类的工具lsof附加到特定进程 ID (PID) 并列出信息或监视它。

我将讨论这两个问题,但首先,我将讨论作业队列,因为我怀疑这就是您正在寻找的队列。

背景 - 作业队列

在类 Unix 操作系统中,您通常会看到作业的概念。在我使用过的大多数类 Unix 操作系统中,它们通常都以类似的方式工作。也就是说,它们可以在后台运行并在队列(作业队列)中分配一个编号,并且可以根据该作业队列中它们的编号的上下文对它们进行操作。

为了将某些内容放入作业队列,他们通常将此行为称为后台处理。当您恢复已在后台运行的作业时,您将其称为前台处理。通常执行此操作的命令bgfg。您还可以使用&运行的任何命令末尾的“&”符号立即将作业放入后台。

例子

工作

$ 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,

笔记:在这里您可以看到它正在等待readfor 命令。这就是终端/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

一旦进程被否认,您就不能再使用jobsfgbg命令对其进行操作。它不再与您当前 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

相关内容