bg 命令详解与参数实测(Ubuntu 22.04)

基于 Ubuntu 22.04(bash 5.1)逐项实测 bg:Stopped 作业恢复为后台运行、无参数取当前作业 %+、bg %1 %2 批量恢复、与 & 直接后台的等效性、already in background 与 no job control 报错形态,以及 bg 后接 disown 防断连收尾。

Linux命令Linux系统UbuntuUbuntu 22.04命令行进程管理2026/10/15

bg 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 bg 的每一种用法——把 Stopped 作业恢复为后台运行、bg %N 按作业号指定、无参数取当前作业(%+)、批量恢复多个作业、与 & 直接后台的等效关系,以及对 Running 作业执行 bg 的报错处理,全部命令与回显已在 Ubuntu 22.04(bash 5.1)实测通过。

一、环境信息

本文所有命令与回显均在以下环境实测采集,读者在相同版本的 Ubuntu 上可直接复现:

项目实测值
操作系统Ubuntu 22.04.5 LTS
架构x86_64
ShellGNU bash,版本 5.1.16(1)-release
bg 命令类型shell builtin(Shell 内置命令,非外部可执行文件)
实测演示目录/root/demo/bg

确认命令与实测回显如下:

$ head -2 /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"

$ uname -m
x86_64

$ echo "BASH_VERSION=$BASH_VERSION"
BASH_VERSION=5.1.16(1)-release

$ type bg
bg is a shell builtin

💡 说明:bg 是 bash 内置命令,只能由 shell 自身执行(它要操纵的是 shell 的作业表并向作业进程组发送 SIGCONT),没有独立的 bg 可执行文件,也没有 --version 类选项;版本信息即 bash 版本(见 2.3 节)。

二、命令概览

2.1 语法与测试数据

本节给出 bg 的语法形态,并准备演示目录。bg 的语法:

bg [job_spec ...]

用法速览:

用法作用实测结论
bg %N把作业号为 N 的 Stopped 作业恢复为后台运行输出 [N]+ cmd &,状态转 Running
bg(无参数)取「当前作业」(%+,带 + 标记者)等价 bg %+
bg %1 %2批量恢复多个 Stopped 作业支持多作业号,逐个恢复
对 Running 作业目标已在后台运行报 job N already in background(rc=0)
对不存在的作业引用无效作业号报 no such job(rc=1)
无作业控制非交互 shell 默认形态报 no job control(rc=1)

准备演示目录:

$ mkdir -p /root/demo/bg && cd /root/demo/bg && pwd
/root/demo/bg

关键差异:bg 的定位是「恢复已被暂停的作业」,它与 & 的分工在于时机——& 是启动时就放后台,bg 是启动后(被 Ctrl-Z 或 SIGSTOP 暂停)再转回后台;对本来就 Running 的后台作业执行 bg 没有意义,bash 会给出 already in background 提示(3.2 节实测)。

💡 技术拓展:让程序「不占用终端继续跑」的方式不止 bg 一种,按「是否依赖当前会话」横向对比——

方式原理会话断开后典型场景
cmd &启动即放后台,仍属当前会话作业表可能收到 SIGHUP 被终止短时后台任务
Ctrl-Z → bg前台暂停后转后台(bg 的标准路径)同上跑到一半才发现要腾出终端
nohup cmd &忽略 SIGHUP,输出写入 nohup.out存活断网/关终端跑长任务
disown %N事后把作业从作业表摘除存活作业已启动才想起要防断连
setsid cmd &新会话新进程组,彻底脱离终端存活守护化启动

本文主角 bg 服务于「当前会话内前台/后台的调度」;防断连场景见上表后两行,nohup 的完整用法见同专栏《nohup 命令详解与参数实测(Ubuntu 22.04)》篇。

2.2 help 全量输出

bg 是内置命令,帮助信息通过 help bg 获取。以下为实测的完整输出(逐行照抄):

$ help bg
bg: bg [job_spec ...]
    Move jobs to the background.
    
    Place the jobs identified by each JOB_SPEC in the background, as if they
    had been started with `&'.  If JOB_SPEC is not present, the shell's notion
    of the current job is used.
    
    Exit Status:
    Returns success unless job control is not enabled or an error occurs.

输出解读:bg 接受多个 JOB_SPEC(复数形态,对比 fg 的单数),语义是「如同用 & 启动一样」把作业放到后台;不带参数时取「当前作业」。退出码:除非作业控制未开启或出错,否则返回成功——注意「目标已在后台运行」的 already in background 不算 error,rc 仍为 0(3.2 节实测)。

2.3 版本信息

bg 无独立版本号,其能力由 bash 决定。实测版本确认:

$ bash --version | head -1
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

$ echo $BASH_VERSION
5.1.16(1)-release

三、参数逐项实测

本章按「无作业控制反例 → Running 反例 → Stopped 恢复主线 → 批量恢复 → 引用形态 → disown 收尾」的顺序逐项实测,每项均附真实回显。

3.1 前置反例一:无作业控制时 bg 报错

在脚本等非交互 shell 中(作业控制默认关闭),bg 完全不可用。先确认选项串(无 m 即无作业控制):

$ echo "当前 \$- 选项串: $-"
当前 $- 选项串: hB

即便作业表里有活着的后台作业,bg 也一律报错。为贴近读者终端形态,此处用 bash -c 载体实测(报错前缀为 bash: line 1:;脚本文件内执行时前缀为脚本名与行号,交互终端则为 bash:):

$ bash -c 'bg; echo rc=$?'
bash: line 1: bg: no job control
rc=1

💡 要点:no job control 不是「没有作业」,而是「当前 shell 没开作业控制」。脚本里要用 bg,开头加 set -m(monitor mode);交互式终端天然可用。本篇后续实测均在 set -m 下进行。

3.2 前置反例二:对 Running 作业执行 bg

开启作业控制后,一个本来就在后台运行的作业再执行 bg,bash 给出提示性报错(rc=0,不算失败)。先看作业表里的 Running 作业:

$ set -m

$ sleep 300 &

$ jobs -l
[1]+   462 Running                 sleep 300 &

执行 bg 触发提示。为贴近读者终端形态,此处用 bash -c 载体实测(报错前缀为 bash: line 1:;脚本文件内执行时前缀为脚本名与行号,交互终端则为 bash:):

$ bash -c 'set -m; sleep 60 & bg %1; echo rc=$?; kill %1'
bash: line 1: bg: job 1 already in background
rc=0

输出解读:报错文本直白——作业已在后台,无需恢复;rc=0 与 help bg 的退出码规则一致(这不算 error)。目标作业状态不受影响,仍是 Running。

💡 要点:看到 already in background 先检查目标状态——多半是 Ctrl-Z 没按(作业根本没暂停),或者作业号写错指向了另一个 Running 作业。

3.3 主线用法:bg 把 Stopped 作业恢复为 Running

bg 的标准路径:作业处于 Stopped 状态 → bg 恢复其在后台运行。先制造 Stopped(交互式终端按 Ctrl-Z 的效果与此等效,脚本中以 kill -STOP 实现):

$ sleep 301 & kill -STOP %+

$ jobs -l
[1]+   464 Stopped (signal)        sleep 301

执行 bg %+,作业被 SIGCONT 唤醒并在后台继续运行:

$ bg %+
[1]+ sleep 301 &

$ jobs -l
[1]+   464 Running                 sleep 301 &

输出解读:bg 输出 [1]+ sleep 301 &——作业号加命令行加 &,与 & 直接后台启动时的回显一致,返回码为 0;jobs -l 复核状态从 Stopped (signal) 变为 Running,PID 464 不变(同一进程被唤醒而非重启)。验证后清理:

$ kill %+; sleep 0.3; jobs
[1]+  Terminated              sleep 301

💡 要点:交互式终端里「Ctrl-Z → bg」是与「Ctrl-Z → fg」并列的两个出口——fg 回前台接着跑,bg 转后台接着跑。bg 发送 SIGCONT 使暂停进程恢复,但不把作业调到前台,终端继续可用。

3.4 & 直接后台与 STOP→bg 的等效性

cmd & 与「暂停后 bg」最终都得到 Running 状态的后台作业。对比实测,先看 & 直接后台:

$ sleep 302 &

$ jobs -l
[1]+   466 Running                 sleep 302 &

再看「启动后暂停、再 bg 恢复」:

$ sleep 303 & kill -STOP %+

$ jobs -l
[1]-   466 Running                 sleep 302 &
[2]+   467 Stopped (signal)        sleep 303

$ bg %+

$ jobs -l
[1]-   466 Running                 sleep 302 &
[2]+   467 Running                 sleep 303 &

两条路径的终点完全一致:[2]+ 467 Running sleep 303 &。区别只在中间多了一步暂停——这正是交互场景的价值:程序已经在前台跑起来才发现要腾出终端,Ctrl-Z(等效 kill -STOP)加 bg 就是补救手段,不需要杀掉重来。清理:

$ kill %+ %-; sleep 0.3; jobs
[1]-  Terminated              sleep 302
[2]+  Terminated              sleep 303

3.5 批量恢复:bg %1 %2

bg 支持一次恢复多个 Stopped 作业。启动两个并全部暂停(用明确的作业号 %1 %2,避免 %+/%- 指针歧义):

$ sleep 304 & sleep 305 &

$ kill -STOP %1 %2

$ sleep 0.3; jobs -s
[1]+  Stopped                 sleep 304
[2]-  Stopped                 sleep 305

批量恢复并复核:

$ bg %1 %2
[1]+ sleep 304 &
[2]+ sleep 305 &

$ sleep 0.3; jobs -l
[1]-   469 Running                 sleep 304 &
[2]+   470 Running                 sleep 305 &

$ kill %+ %-; sleep 0.3; jobs
[1]-  Terminated              sleep 304
[2]+  Terminated              sleep 305

输出解读:bg %1 %2 逐个恢复并各输出一行 [N]+ cmd &;jobs -l 确认两个作业都回到 Running。注意暂停与恢复之间用 sleep 0.3 留出信号处理窗口,否则可能读到未刷新的旧状态(见 5.3 节)。

💡 要点:批量操作时优先用明确的 %N 作业号而非 %+/%-——bg 恢复一个作业后,当前/上一作业指针会重排,混合使用相对引用容易出现「第二个参数指向刚恢复的作业」的意外(此时报 already in background)。

3.6 引用形态:无参数取 %+、按名匹配、无效作业号

无参数 bg 等价 bg %+,取当前作业。完整链路(含返回码与复核)实测:

$ set -m; sleep 308 & kill -STOP %+; bg; echo rc=$?; jobs -l; kill %+; sleep 0.3; true
[1]+ sleep 308 &
rc=0
[1]+   194 Running                 sleep 308 &
[1]+  Terminated              sleep 308

输出解读:无参数 bg 恢复了暂停中的当前作业([1]+ sleep 308 &),rc=0;jobs -l 确认 Running;最后 kill 收尾打印 Terminated。

对不存在的作业号报错(为贴近读者终端形态,此处用 bash -c 载体实测):

$ bash -c 'set -m; bg %3; echo rc=$?'
bash: line 1: bg: %3: no such job
rc=1

按命令名匹配与 fg 一致,bg %name 同样可用(匹配规则与歧义处理详见《jobs 命令详解与参数实测(Ubuntu 22.04)》篇 3.7 节)。

3.7 无作业时 bg 报错

作业表为空(或当前作业不存在)时,无参数 bg 报错、rc=1:

$ bash -c 'set -m; bg; echo rc=$?'
bash: line 1: bg: current: no such job
rc=1

3.8 bg 之后接 disown:脱离作业表

bg 恢复的作业仍是会话内的普通后台作业,会随会话结束收到 SIGHUP;若要防断连,可接 disown 把它从作业表摘除。完整链路:启动 → 暂停 → bg 恢复 → disown:

$ sleep 307 & kill -STOP %+; bg %+; PID307=$!
[1]+ sleep 307 &

$ disown $PID307

$ jobs; echo "rc=$?"
rc=0

作业表已空,但进程还在(STAT 为 S,即 sleep 的正常等待态):

$ ps -o pid,ppid,pgid,stat,cmd -p $PID307
    PID    PPID    PGID STAT CMD
    476     451     476 S    sleep 307

验证后清理:

$ kill $PID307; sleep 0.3; echo "清理 rc=$?"
清理 rc=0

💡 要点:disown 用 $!(最后启动的后台进程 PID)而非作业号引用——bg 操作不改变 $! 的指向,这一写法在批量脚本里比作业号更可靠。

四、实战示例

本章给出 4 个以 bg 为核心的组合场景,全部为实测原样回显。

4.1 交互场景:前台跑到一半转后台

交互终端里最经典的补救操作:命令已经在前台执行才发现需要腾出终端,按 Ctrl-Z 暂停(本环境用 kill -STOP 等效模拟)再 bg 恢复,程序无感知地继续跑(完整回显见 3.3 节实测):

$ sleep 301 & kill -STOP %+

$ jobs -l
[1]+   464 Stopped (signal)        sleep 301

$ bg %+
[1]+ sleep 301 &

$ jobs -l
[1]+   464 Running                 sleep 301 &

要点:Ctrl-Z 暂停不会终止进程(状态是 Stopped 而非 Terminated),bg 恢复后 PID 不变、进度不丢。

4.2 多任务并行:批量暂停批量恢复

批量后台任务的「全停再全开」流程,配合 jobs -s 过滤 Stopped 状态作业:

$ sleep 304 & sleep 305 &

$ kill -STOP %1 %2

$ sleep 0.3; jobs -s
[1]+  Stopped                 sleep 304
[2]-  Stopped                 sleep 305

$ bg %1 %2
[1]+ sleep 304 &
[2]+ sleep 305 &

要点:jobs -s 只列 Stopped 作业,天然就是「待恢复清单」;bg 支持的复数 job_spec 让批量恢复一条命令完成。

4.3 & 与 bg 的选型对照

两种后台化路径的完整对照实测见 3.4 节:sleep 302 & 与 sleep 303 & kill -STOP %+ → bg %+ 的终点回显一致(Running ... &)。选型口诀:启动时就知道要后台,直接 &;跑起来才要腾终端,Ctrl-Z 加 bg。两者都是会话内作业,防断连需求再叠加 nohup 或 disown(2.1 节拓展表)。

4.4 bg 恢复后防断连收尾

bg 恢复的长任务若担心会话断开被杀,接 disown 摘除作业表关联,完整链路实测见 3.8 节(bg 后 disown $PID,jobs 清空而 ps 确认进程存活)。若任务尚未启动,更优雅的做法是启动时就用 nohup cmd &(见同专栏《nohup 命令详解与参数实测(Ubuntu 22.04)》篇)。

五、注意事项与常见问题

5.1 脚本里必须 set -m(no job control 踩坑)

Q1:为什么我在脚本里用 bg 报 no job control?

非交互 shell 默认关闭作业控制(echo $- 中没有 m,实测为 hB),bg 作为作业控制的核心命令直接不可用。解法二选一:脚本开头加 set -m;或改在交互式终端操作。实测见 3.1 节。注意脚本中即使作业表有作业(jobs 能看到),bg 依旧报错——「有作业表」与「作业控制开启」是两回事。

5.2 already in background 不是故障

Q2:bg: job 1 already in background 是出错了吗?

是提示不是故障,退出码为 0(3.2 节实测)。它表示目标作业本来就 Running,无需也不存在「恢复」动作。常见原因:忘记先 Ctrl-Z/kill -STOP 暂停,或 %+ 指向了刚被 bg 恢复的作业。真正的错误(无此作业、无作业控制)退出码才是 1。

5.3 信号与状态刷新时序

Q3:kill -STOP %1 之后 jobs 还显示 Running?

信号发出到 shell 收割 SIGCHLD、刷新作业状态之间存在毫秒级窗口。本篇 3.5、3.6 节的 sleep 0.3 缓冲即为稳定回显而加;批量暂停后立即 bg 也可能因状态未刷新而报 already in background——先缓冲再操作。

Q4:Ctrl-Z 和 kill -STOP 一样吗? 效果等价(进程进入暂停态,jobs 显示 Stopped),机制有别:Ctrl-Z 发送 SIGTSTP(可被进程捕获),SIGSTOP 不可捕获、不可忽略。脚本自动化只能用后者。

5.4 与相邻命令的分工

Q5:bg、fg、& 该怎么选? 三者是同一套作业控制机制的不同入口:& 启动即后台,bg 把暂停作业转后台,fg 把后台/暂停作业调前台。三者都依赖作业控制开启(交互终端默认开启,脚本需 set -m),都用同一套 jobspec 语法。

Q6:bg 恢复的作业会随终端关闭死掉吗? 会。bg 只改变「前台/后台」形态,不改变作业与会话的从属关系,会话退出时后台作业可能收到 SIGHUP。需要跨会话存活,用 nohup cmd &、disown %N 或 setsid(横向对比见 2.1 节拓展表)。

Q7:bg 能一次恢复多个作业吗? 能,这是 bg 与 fg 的语法差异之一:bg [job_spec ...] 复数(bg %1 %2 批量恢复实测见 3.5 节),fg [job_spec] 单数。

六、参考链接