前面在 《Linux Systemd 服务注册指南》 一文中介绍了linux上如何注册Systemd 服务,但真到了临时跑个脚本的时候,systemd 反而太重了。这时候就该 nohup 出场。本文从 systemd 引申到 nohup,讲透原理、标准写法、使用场景与常见坑。
一、什么是 nohup
nohup 是 "No Hang Up"(不挂断)的缩写,是 Linux/Unix 系统中用于在后台不挂断运行命令的工具。其核心功能是使进程忽略 SIGHUP(挂断)信号,确保在用户退出登录、关闭终端或 SSH 断开后,进程仍能继续运行。
二、工作原理
1. 信号屏蔽机制
当终端关闭或用户注销时,Shell 会向其所有子进程发送 SIGHUP 信号,导致进程终止。nohup 通过调用 signal(SIGHUP, SIG_IGN) 将进程对 SIGHUP 信号的处理方式设置为忽略,使进程不受终端断开的影响。
2. 输入输出重定向机制
- 标准输入(stdin,文件描述符 0) :默认重定向到
/dev/null,避免进程因等待输入而阻塞。 - 标准输出(stdout,文件描述符 1) :默认重定向到当前目录下的
nohup.out文件;若当前目录不可写,则重定向到$HOME/nohup.out。 - 标准错误(stderr,文件描述符 2) :默认合并到标准输出,一并写入
nohup.out文件。
3. 退出状态码
| 退出状态 | 含义 |
|---|---|
| 125 | nohup 本身执行失败 |
| 126 | 能找到命令但无法调用执行 |
| 127 | nohup 出错或找不到指定命令 |
| 其他 | 返回所执行命令的退出状态 |
三、基本语法
bash
nohup COMMAND [ARG...] [> output_file 2>&1] [&]
四、常用参数与选项
| 参数 | 说明 |
|---|---|
& |
将命令放入后台执行(nohup 本身不自动后台运行,需配合 & 使用) |
> file |
重定向标准输出到指定文件 |
2>&1 |
将标准错误重定向到标准输出,合并日志 |
/dev/null |
丢弃所有输出,不生成日志文件 |
-p pid |
修改指定已运行进程以忽略 SIGHUP 信号(部分系统如 AIX、Oracle 支持) |
-g gpid |
对指定进程组执行忽略 SIGHUP 操作 |
-a |
强制更改信号处理,即使进程已安装处理程序 |
-F |
强制抓取目标进程控制权 |
五、常用执行方式
1. 基础后台运行
bash
nohup command &
2. 自定义日志文件(推荐)
bash
nohup command > output.log 2>&1 &
其中 > output.log 重定向标准输出,2>&1 将标准错误合并至标准输出,& 表示后台执行。
3. 丢弃所有输出
bash
nohup command > /dev/null 2>&1 &
4. 分离输出与错误日志
bash
nohup command > stdout.log 2> stderr.log &
5. 追加模式写入日志
bash
nohup command >> output.log 2>&1 &
6. 运行复杂命令
bash
nohup sh -c 'cd /path/to/dir && command1 && command2' > log.txt 2>&1 &
六、典型应用场景
- 远程服务器上执行长时间任务:如数据备份、模型训练、编译、数据迁移等。
- 启动后台服务或守护进程:如 Java 服务、Web 应用、Python 脚本等。
- 系统维护与自动化脚本执行:如 rsync 数据同步、数据库维护等。
常见示例
bash
# 后台运行 Java 应用
nohup java -jar app.jar > app.log 2>&1 &
# 后台运行 Python 脚本
nohup python3 train.py > train.log 2>&1 &
# 后台运行 Shell 脚本
nohup ./backup.sh > backup.log 2>&1 &
# 后台运行数据同步任务
nohup rsync -av /data /backup > sync.log 2>&1 &
七、进程管理
1. 查看进程
bash
# 查看系统进程
ps -ef | grep "command"
ps aux | grep command
pgrep -a command
# 查看当前会话后台任务(仅当前终端有效)
jobs -l
2. 终止进程
bash
# 优雅终止
kill PID
# 强制终止
kill -9 PID
3. 实时查看日志
bash
tail -f nohup.out
tail -f output.log
八、注意事项
1. nohup 与 & 的关系
&仅将命令放入后台运行,终端关闭后进程会因 SIGHUP 信号而终止。nohup仅忽略 SIGHUP 信号,默认在前台运行,会阻塞终端。- 两者结合(
nohup command &)才是生产环境最常用的组合:后台运行 + 防挂断。
2. 日志管理
- 默认的
nohup.out文件可能无限增长,需定期清理或使用logrotate进行日志轮转,防止磁盘占满。 - 推荐显式指定输出文件路径,便于日志管理。
- 不要直接
rm删除正在写入的nohup.out,可能导致进程无法继续写入日志。正确做法是使用> nohup.out清空文件内容。
3. 权限问题
- 确保日志输出目录具有写入权限,否则命令可能执行失败。
- 确保对目标程序有执行权限。
4. 工作目录问题
- 若脚本中使用相对路径,需在脚本所在目录执行
nohup,或改用绝对路径。 - 指定工作目录的方式:
bash
cd /path/to/dir && nohup command > log.txt 2>&1 &
5. 输出缓冲问题
- Python 等语言存在输出缓冲,需加
-u参数实现实时日志:
bash
nohup python -u script.py > output.log 2>&1 &
6. 信号免疫范围
nohup仅忽略 SIGHUP 信号,不免疫 SIGTERM、SIGKILL 等其他终止信号。
九、替代方案对比
| 特性 | nohup | screen/tmux | systemd |
|---|---|---|---|
| 核心功能 | 忽略 SIGHUP 信号 | 创建持久化虚拟终端会话 | 系统级服务管理 |
| 交互性 | 无,启动后无法再交互 | 有,可随时重连会话 | 无 |
| 开机自启 | 不支持 | 不支持 | 支持 |
| 崩溃重启 | 不支持 | 不支持 | 支持 |
| 日志管理 | 手动管理 | 手动管理 | 统一日志管理(journalctl) |
| 易用性 | 非常简单,一条命令 | 中等,需学习基本命令 | 较复杂,需编写服务文件 |
| 适用场景 | 一次性、无需交互的长期任务 | 需要调试、交互、多任务管理 | 生产环境关键服务 |
简单选择建议
- 跑一个脚本,不需要再管它 :用
nohup最快捷。 - 需要随时查看进度、进行调试 :用
screen或tmux。 - 生产环境关键服务 :推荐使用
systemd管理。
十、补充:disown 与 setsid
disown 命令
如果已经启动了一个后台进程(使用 &),可以使用 disown 将其从当前 Shell 会话的作业表中移除,使其不受终端关闭的影响:
bash
command &
disown %1
setsid 命令
setsid 会创建一个新的会话组,使进程不再与任何终端关联,实现彻底脱离终端:
bash
setsid nohup command [args] &
总结
nohup 是 Linux 系统中最简单直接的后台持久运行工具。核心用法一句话概括:想跑不怕关终端,就在命令前面加个 nohup,后面加个 &。
推荐的标准写法:
bash
nohup command > output.log 2>&1 &