我如何在Linux中对Shell进行多项工作

时间:2018-11-16 03:59:22

标签: linux exception process linux-kernel

我是Linux的初学者,只是对工作和流程组有一些疑问。

我的教科书说'Unix外壳使用作业的抽象来表示由于评估单个命令行而创建的进程。在任何时间点,最多有一个前台作业,而零个或多个后台作业。

可以说我们有这个简单的shell代码(我省略了一些不重要的代码,例如,设置argv等): enter image description here

enter image description here

当我们输入第一个命令时,例如:./exampleProgram &

Q1-是否创建工作?如果是,该作业包含什么过程?

shellex.c的main()被调用,因此在执行第15行时:fork()创建一个新的子进程,假设父进程为p1,而新创建的子进程为c1 如果它是后台作业,那么我们可以在提示符./anotherProgram &中键入另一个命令,然后键入Enter

Q2-我很确定,现在它只是p1和c1,并且p1正在执行第二条命令,当它再次执行第15行时:fork(), 我们有p1,c1和新创建的c2,我的理解正确吗?

Q3-有多少工作?仅仅是包含p1,c1和c2的一项工作吗?

Q4-如果它只是一个作业,那么当我们继续键入新命令时,我们将只有一个作业包含一个父进程p1和许多子进程c1,c2,c3,c4 ... 那么为什么我的教科书上说壳牌可以做一份以上的工作呢?以及为什么最多有一个前台作业和零个或多个后台作业。

2 个答案:

答案 0 :(得分:2)

关于这个话题,有很多话要说,其中一些可以作为答案,而大多数都需要进一步阅读。

对于第一季度,我从概念上说可以,但是作业不是自动的,作业跟踪和控制也不是不可思议的。我没有看到您显示的代码片段中的任何逻辑,例如建立并维护一个工作表。我了解这只是一个示例,因此工作控制逻辑可能在其他地方。作业控制是现有的普通Unix Shell的功能,但是如果人们从头开始编写新的Unix Shell,则需要添加作业控制功能,如代码/逻辑。

对于第二季度,您所说的方式不是我所说的。在第一次调用fork()之后,是的,有一个p1和一个c1,但是首先要认识到p1和c1是 same 程序(shellex)的不同实例。 ;仅在对execve()的调用正在运行exampleProgram之后。 fork()创建shellex的子实例,而execve()导致shellex的子实例被exampleProgram替换(在RAM中)(假设是值argv[0])。

父母没有“处决”孩子的真实含义,也没有在execve()上替换孩子的过程,只是为了让他们继续前进。父级启动子级,并可能等待完成子级执行,但实际上,父级及其子进程的整个层次结构都是各自独立执行的,正在执行通过内核。

但是,是的,如果告诉运行的程序应该在后台运行,那么shellex将接受进一步的输入,并且在下一次调用fork()时,将有父级{{ 1}}和两个子进程。再一次,首先,子c2将是shellex的实例,并通过shellex迅速替换为已命名的任何程序。

(关于在后台运行,execve()是否起作用取决于示例代码中名为&的函数内部的逻辑。我熟悉{{1} }表示“在后台运行”,但这并没有什么特别的或不可思议的,新编写的Unix shell可以以其他方式做到这一点,即在结尾parseline()或前导{{1} }或Shell作者决定做的任何事情。

对于 Q3 Q4 ,首先要认识到的是您正在调用的父级& shell程序您所显示的。因此,不,+不会成为工作的一部分。

在Unix中,作业是作为单个管道的一部分执行的进程的集合。因此,一项工作可以包含一个或多个过程。此类进程仍附加到运行它们的终端,但可能在前台(正在运行和交互式),已挂起或在后台(正在运行而不是交互式)。

BG:

要凭经验查看作业与流程,请在后台运行管道(上述5个示例中的第5个),并且在运行时使用p1向您显示流程ID和流程组ID。例如,在我Mac的bash版本上,是:

p1

与外壳和终端的此附件相反,守护程序从两者分离。启动守护程序时,父级使用one process, foreground : ls -lR one process, background : ls -lR & one process, background : ls -lR, then CTRL-Z, then bg many processes, foreground : ls -lR | grep perl | sed 's/^.*\.//' many processes, background : ls -lR | grep perl | sed 's/^.*\.//' & 来启动子进程,但随后退出,仅使子级运行,并且现在使用父级PID1。子级关闭ps,{{ 1}}和$ ls -lR | grep perl | sed 's/^.*\.//' & [1] 2454 <-- job 1, PID of the sed is 2454 $ ps -o command,pid,pgid COMMAND PID PGID vim 2450 2450 <-- running in a different tab ls -lR 2452 2452 } grep perl 2453 2452 }-- 3 PIDs, 1 PGID sed s/^.*\.// 2454 2452 } ,因为它们毫无意义,因为守护程序运行“无头”。

但是在外壳程序中,父级(又是外壳程序)保持运行fork() ing(前台子程序)或不运行stdin ing(后台子程序),并且孩子通常会保留使用stdoutstderrwait()(尽管这些孩子可能会被重定向到文件等)

而且,外壳程序可以调用子外壳程序,当然,任何运行的程序都可以wait()自己的子进程,依此类推。因此,流程的层次结构会变得很深。如果没有其他特定操作,子进程将与其父进程位于同一进程组中。

这里有一些文章可供进一步阅读:

What is difference between a job and a process in Unix?

https://unix.stackexchange.com/questions/4214/what-is-the-difference-between-a-job-and-a-process

https://unix.stackexchange.com/questions/363126/why-is-process-not-part-of-expected-process-group

Bash Reference Manual; Job Control

Bash Reference Manual; Job Control Basics

答案 1 :(得分:0)

工作不是Linux的事情,它不是后台进程,而是您的特定shell 定义为“工作”的东西。

通常,shell引入“作业”的概念来执行作业控制。这通常包括一种识别作业并对其执行操作的方法,例如

  • 进入前景
  • 放入背景
  • 停止
  • 恢复
  • 杀死

如果shell无法执行任何上述操作,那么谈论工作就没有意义了。