# 工作管理(job control)

是在 bash 环境下的概念,当我们登录系统取得 bash shell 后,在单一终端机下同时进行多个工作的行为管理。

# 什么是工作管理?

进行工作管理的行为中,其实每个工作都是目前 bash 的子进程,彼此之间是有相关性的。我们无法以 job control 的方式由 tty1 的环境去管理 tty2 的 bash

为什么会有工作管理?系统有多个 tty 使用,这样切换很麻烦,还有之前讲解的 /etc/security/limits.conf(第 13 章)可以设置同时登录的联机数量,假设只允许一个呢?

假设我们只有一个终端机接口,因此在可以出现提示字符让你操作的环境称为 前景 foreground,其他工作可以放入 背景 background 去暂停或运行。要注意的是:放入背景的工作在运行时,不能与使用者互动。比如 vim 不能再背景里面执行(running)的,因为你没有输入数据它就不会运行。而且放入背景的工作是不可以使用 ctrl+c 来终止的

进行 bash 的 job control 必须要注意的限制是:

  • 这些工作所触发的进程必须来自于你的 shell 的子进程(只管理自己的 bash)
  • 前景 foreground:你可以控制与下达指令的环境
  • 背景:可以自动运行的工作,你无法使用 ctrl + c 终止它,可以使用 bg、fg 呼叫该工作
  • 背景中执行的进程不能等待 terminal/shell 的输入(input)

# job control 的管理

# 直接将指令丢到背景中 执行&

# 使用 & 将 /etc/ 整个备份为 /tmp/etc/tar.gz 工作丢到背景中执行
# 原因就是,压缩费时,不想一直就在当前界面看着他完成
[root@study ~]# tar -zpcf /tmp/etc.tar.gz /etc &
[1] 19763			# job number 与 PID
[root@study ~]# tar: Removing leading `/' from member names
# PID 与 bash 的控制有关,后续出现的数据信息是 tar 执行的数据流
# 由于没有加上数据流重导向,所以会影响画面,不过不会影响前景的操作

# 那他什么时候完成呢?当你输入几个指令后,发现出现了这一行
# 那么久表示在背景中的工作已经完成了
[1]+  Done                    tar -zpcf /tmp/etc.tar.gz /etc
1
2
3
4
5
6
7
8
9
10
11

[1]+ 表示这个工作已经完成(Done),后面是具体的指令串。如果有有信息出现,那么你的前景会出现干扰,只需要按下 enter 键就会出现提示字符,更下下指令

[root@study ~]# tar -zpcvf /tmp/etc.tar.gz /etc &
1

由于输出了信息,stdout 和 stderr 都会输出到屏幕上,这样就会影响前景终端,所以一般都利用数据流重导向,将输出数据传送至某个文件中,比如

[root@study ~]# tar -zpcvf /tmp/etc.tar.gz /etc  > /tmp/log.txt 2>&1 &
[1] 16592
[root@study ~]# 
1
2
3

#目前 的工作丢到背景中_暂停_:ctrl+z

考虑这个场景,我正在使用 vim,却发现某个文件的路径不记得了,需要到 bash 环境下进程搜索,此时不需要结束 vim,可以把它丢到背景中等待

[root@study ~]# vim ~/.bashrc 
# 在 vim 环境下按 ctrl + z 组合键
[2]+  Stopped                 vim ~/.bashrc
[root@study ~]# 		# 这就取得了前景
[root@study ~]# find / -print
# 会大量输出信息,我们把这个工作也丢到背景中执行
[3]+  Stopped                 find / -print
[root@study ~]# 
1
2
3
4
5
6
7
8

[2]+ 表示这个是加入到背景中的第二个工作,Stopped 是状态,预设情况下,使用 ctrl+z 丢到背景中的工作都是暂停状态

# 观察目前的背景工作状态:jobs

jobs [-lrs]

选项与参数:
	-l:除了列出 job number 与指令之外,同时列出 PID 的号码
	-r:仅列出正在背景 run 的工作
	-s:仅列出正在背景中暂停 stop 的工作
1
2
3
4
5
6
# 范例 1:观察目前的 bash 中,所有工作与队友的 PID
[root@study ~]# jobs -l
[2]- 26476 Stopped                 vim ~/.bashrc
[3]+  2207 Stopped                 find / -print
1
2
3
4

仔细看上面有减号和加号:

  • +:表示最近被放到背景的工作;如果只输入 fg 指令,那么 [3] 会被拿到前景中来处理
  • -:表示最近最后第二个被放置到背景中的工作。如果超过最后第三个以后的工作,就不会有 -、+ 符号了

# 将背景工作拿到前景来处理:fg

fg %jobnumber

$jobnumber: jobnumber 是工作号码(数字),哪个 % 是可有可无的
1
2
3
# 范例 1:先以 jobs 管擦工作,再将工作取出
[root@study ~]# jobs -l
[2]- 26476 Stopped                 vim ~/.bashrc
[3]+  2207 Stopped                 find / -print
# 取出 + 号的工作,注意会刷屏,马上按下 ctrl + z ,再次放入到背景中
[root@study ~]# fg
# 直接取出 2 的工作,在放到背景中
[root@study ~]# fg %2
vim ~/.bashrc

[2]+  Stopped                 vim ~/.bashrc
[root@study ~]# jobs -l
[2]+ 26476 Stopped                 vim ~/.bashrc
[3]-  2207 Stopped                 find / -print

# 可以看到, 2 的工作被标记为了 + 号,表示是最近放进去的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 让工作在背景下的状态变成运行中:bg

# 范例 1: 执行 find / -perm /7000 > /tmp/text.txt,立刻丢到背景去暂停
[root@study ~]# find / -perm /7000 > /tmp/text.txt
find: '/proc/29541/task/29541/fd/5': No such file or directory
find: '/proc/29541/task/29541/fdinfo/5': No such file or directory
find: '/proc/29541/fd/6': No such file or directory
find: '/proc/29541/fdinfo/6': No such file or directory
^Z
[4]+  Stopped                 find / -perm /7000 > /tmp/text.txt

# 范例 2:让该工作在背景下进行,并且观察他
[root@study ~]# jobs ; bg %4; jobs
[2]-  Stopped                 vim ~/.bashrc
[3]   Stopped                 find / -print
[4]+  Stopped                 find / -perm /7000 > /tmp/text.txt

[4]+ find / -perm /7000 > /tmp/text.txt &
[2]+  Stopped                 vim ~/.bashrc
[3]   Stopped                 find / -print
[4]-  Running                 find / -perm /7000 > /tmp/text.txt &
# 第 4 个由 Stopped 变成了 Running 状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 管理背景中的工作:kill

通过 fg 拿到前景来,可以通过 kill 将该工作直接移除

kill -signal $jobnumber
kill -l

选项与参数:
	-l:L 的小写,列出目前 kill 能够使用的信号(signal)有哪些?
	signal:给予后续工作什么指示,用 man 7 signal 可知:
		-1:重新读取一次参数的配置文件(类似 reload)
		-2:代表与由键盘输入 ctrl+c 同样的动作
		-9:立刻强制删除一个工作
		-15:已正常的进程方式终止一项工作。与  -9 是不一样的
1
2
3
4
5
6
7
8
9
10
范例 1: 找出目前 bash 环境下的背景工作,并将该工作 强制删除
[root@study ~]# jobs
[2]+  Stopped                 vim ~/.bashrc
[3]   Stopped                 find / -print
[4]-  Exit 1                  find / -perm /7000 > /tmp/text.txt

[root@study ~]# kill -9 %3; jobs
[2]+  Stopped                 vim ~/.bashrc
[3]   Killed                  find / -print
# 过几秒再运行 jobs 会发现 killed 的不见了

# 范例 2:找出目前 bash 环境下的而背景工作,并将该工作 正常 终止
[root@study ~]# kill -SIGTERM %2

[2]+  Stopped                 vim ~/.bashrc
[root@study ~]# jobs
[2]+  Stopped                 vim ~/.bashrc
# -SIGTERM 与 -15 同效果,可以用哪个 kill -l 来查阅
# 在这个案例中,会发现 vim 的工作无法被结束,无法通过 kill 正常终止
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

使用 vim 时候,会产生一个 .filename.swp 文件,使用 -15 这个 signal 时,vim 会尝试以正常的步骤来结束掉该 vi 的工作,使用 .filename.swp 会主动的被移除,若是使用 -9,那么 swp 文件不会被移除调用

kill 需要了解 1、9、15 的 signal 的含义,可以用 man 7 signal 查询相关资料,还有一个 killall 也是同样的用法。

kill 后面接的数字,默认是 PID,要管理 bash 的工作控制,需要加上 %数字 的方式

# 脱机管理问题

注意:前面工作管理中的「背景」是指在终端机模式下可以避免「ctrl+c」中断,可以理解为是这个 bash 的背景,并 不是放到系统的背景 中去。所以,工作管理的背景依旧与终端机有关

如果你是以远程方式连接到 Linux 主机,并且将工作以 & 的方式放到背景中去,在工作未结束时,你脱机了,该工作不会继续进行,而是会被中断掉

那么可以使用前一章学习的 at 指令,因为它是将工作放置到系统背景,还可以使用 nohup 指令来达到效果

nohup [指令与参数]		# 在终端机前景中工作
nohup [指令与参数]		# 在终端机背景中工作
1
2

TIP

nohup 后面的指令不支持 bash 内置指令!

#1. 编辑一个会随眠  500 秒的程序
[root@study ~]# vim sleep500.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo "I have sleep 500 seconds."

# 2. 丢到背景中执行
[root@study ~]# chmod a+x sleep500.sh 
[root@study ~]# nohup ./sleep500.sh &
[3] 14915
[root@study ~]# nohup: ignoring input and appending output to 'nohup.out'
1
2
3
4
5
6
7
8
9
10
11

你登出登录后,再次登录系统,使用 pstree (这里没有说是什么)去查询你的进程,会发现它还在执行,还输出了一个信息,nohup 与终端机无关了,因此整个信息的输出就会被导向 ~/nohup.out