bg / fg
bg、fg、jobs 是 shell 的作业控制内建命令,管的是当前这个终端里跑着的任务:把前台任务丢到后台、把后台任务捞回前台、看看手上有几个。
jobs [-l]bg [作业号]fg [作业号]三个都是 shell 内建命令,
which bg查不到,见 which 作业号只在当前 shell 里有效,换一个终端就不认识了
作业的几种写法:
| 写法 | 指代 |
|---|---|
%1 |
作业号为 1 的作业,直接写 1 多数 shell 也认 |
%% 或 %+ |
当前作业,bg、fg 不带参数时的默认对象 |
%- |
上一个作业 |
%字符串 |
命令以该字符串开头的作业 |
作业和进程是两个层面的概念:
- 进程是内核的概念,有全局唯一的 PID
- 作业是 shell 的概念,只在当前 shell 内有意义。一条管道
a | b | c是三个进程,但只是一个作业
前台作业占据终端的输入,shell 会等它结束;后台作业不占输入,shell 立刻回到提示符。但输出是另一回事 —— 后台作业默认仍然共用终端的 stdout 和 stderr,所以它打印的东西会插进你正在敲的命令里。
作业状态的切换靠信号完成:
| 操作 | 实际发生的事 |
|---|---|
Ctrl-Z |
给前台作业发 TSTP,进程进入 T(已停止)状态 |
bg |
发 CONT 让它继续,但不把它放回前台 |
fg |
发 CONT,同时把终端的控制权交回给它 |
Ctrl-C |
发 INT,通常就是终止 |
信号的含义见 kill。
| 命令 | 作用 |
|---|---|
Ctrl-Z |
暂停当前前台作业 |
jobs |
列出当前 shell 的所有作业 |
jobs -l |
同时显示 PID |
bg %1 |
让暂停的作业 1 在后台继续运行 |
fg %1 |
把作业 1 调回前台 |
command & |
启动时就放到后台 |
disown %1 |
把作业从 shell 的作业表里摘掉,关终端时不会被 HUP |
wait |
等所有后台作业结束 |
1. 忘了加 & 的补救
./long-task任务已经跑起来并占着终端,按 Ctrl-Z 再:
bgjobs -l输出:
[1]+ 20481 Running ./long-task &2. 在编辑器和 shell 之间来回切
vim notes.mdCtrl-Z 回到 shell 做点别的,然后:
fg比另开一个终端快,而且编辑器的状态原样保留
3. 关掉终端也要接着跑
./long-task &disown %1或者一开始就想好:
nohup ./long-task > out.log 2>&1 &
disown是事后补救,nohup是事前预防,都是为了挡住终端关闭时的HUP要长期跑的东西还是放进 tmux 更省心,随时能连回去看
4. 后台作业的输出要重定向掉
./task > task.log 2>&1 &不重定向的话,后台作业的输出会直接打到终端上,和你正在输入的命令混成一团 重定向的写法见 stdio
5. 后台作业读输入会被停住
jobs输出:
[1]+ Stopped (tty input) ./interactive后台作业想从终端读输入时会收到
TTIN而被暂停 用fg把它调回前台,输入完再Ctrl-Z+bg送回去
help jobs、help bg、help fg(都是内建命令,man查不到)- Bash Reference Manual – Job Control