Linux 中如何使用 nohup:断开终端后继续运行进程
在 Linux 中,长时间运行的任务经常会遇到同一个问题:终端关闭、SSH 断开、用户退出登录后,任务也跟着结束。nohup 提供了一种直接的处理方式,它让目标进程忽略 SIGHUP 信号,从而在终端会话结束后继续运行。
nohup 适合执行简单、非交互式、需要持续运行的命令。它不是会话管理器,也不负责自动重启,更不能抵抗系统关机或手动强制终止。理解它的边界,比记住命令格式更重要。
nohup 是什么
nohup 是 “no hang up” 的缩写,用来让命令在 shell 或终端退出后继续运行。其核心行为是让进程忽略 SIGHUP(Signal Hang UP)信号。
当终端关闭、SSH 连接中断、用户注销时,shell 通常会收到 SIGHUP,并把这个信号继续发给它启动的子进程。默认情况下,很多进程会因此退出。nohup 的作用就是屏蔽这一路径上的影响。
语法
nohup 的基本语法如下:
nohup command arguments
也可以查看选项:
nohup options
查看版本:
nohup --version
最基本的用法
准备一个简单脚本 hello.sh:
#!/bin/bash
echo "Hello World!"
使用 nohup 执行:
nohup ./hello.sh
如果标准输出和标准错误没有显式重定向,nohup 会把输出写入 nohup.out。默认优先尝试当前目录;如果当前目录不可写,则退回到 $HOME/nohup.out。
查看输出:
cat nohup.out
输出重定向
默认写入 nohup.out 只适合临时使用。实际运维和开发中,通常应显式指定日志文件。
只重定向标准输出
nohup ./hello.sh > output.txt
查看结果:
cat output.txt
将标准输出和标准错误写到同一个文件
nohup ./hello.sh > myoutput.txt 2>&1
这里的 2>&1 表示把标准错误重定向到标准输出当前指向的位置。
分开保存标准输出和标准错误
对于排错更友好的方式是拆分两个流:
nohup ./my_cmd > app.log 2> app.err &
自定义合并日志
nohup ./my_cmd > combined.log 2>&1 &
在后台运行
nohup 只负责忽略 SIGHUP,不会自动把进程放到后台。要立即拿回终端控制权,还需要在命令末尾加 &。
例如:
nohup ping google.com &
这样命令会进入后台执行,shell 提示符会立即返回。
查询进程:
pgrep -a ping
停止进程:
kill 2565
其中 2565 是实际进程 ID。
不加 & 会发生什么
这是一处常见误解。以下命令依然有意义:
nohup ./my_script.sh
此时:
- 进程仍然会忽略
SIGHUP - 如果输出连接到终端,输出仍会被重定向到
nohup.out - 终端不会立刻返回提示符
- 脚本结束前,当前 shell 会一直等待
如果命令尚未结束时终端断开,底层脚本通常仍会继续运行,只是这种用法会阻塞当前终端,因此不常用于日常后台任务。
如果已经这样启动,也可以借助作业控制做进一步分离,例如先按 Ctrl+Z,再执行 bg 和 disown。不过对 SIGHUP 的免疫,nohup 本身已经提供。
nohup 与用户会话的关系
SSH 连接异常中断
网络中断或 SSH 客户端崩溃时,服务端的 SSH 守护进程通常会向登录 shell 发送 SIGHUP。shell 再把这个信号传给子进程。
普通进程会退出,使用 nohup 启动的进程会继续运行。输出会保存在 nohup.out 或自定义日志文件中。
这是 nohup 最典型的使用场景。
正常退出登录
执行 exit 或 logout 时,登录 shell 会结束,并向其子进程发送 SIGHUP。使用 nohup 启动的任务会忽略这个信号,因此在用户退出后仍可继续运行。
关闭终端模拟器窗口
如果是在本地终端中直接运行 nohup,关闭终端窗口通常会导致本地 shell 收到 SIGHUP,再传给其子进程。nohup 启动的进程会继续运行。
如果终端中承载的是 SSH 会话,关闭窗口等价于本地 SSH 客户端退出,远端行为与 SSH 中断相同。远程服务器上的 nohup 进程仍会继续运行。
进程失去原父进程后,其父进程 ID 可能变为 1(init)或其他负责接管孤儿进程的系统进程。
会话超时或空闲超时
某些环境会通过 bash 的 TMOUT 或 SSH 配置在长时间空闲后自动终止会话。底层机制通常仍涉及向 shell 发送 SIGHUP。
这种情况下,nohup 启动的任务仍会继续运行。
系统关机或重启
这是 nohup 的边界之一。系统关机或重启时,操作系统会终止所有进程,常见顺序是先发 SIGTERM,超时后再发 SIGKILL。
nohup 只忽略 SIGHUP,对 SIGTERM 和 SIGKILL 不提供保护。因此:
nohup无法让进程穿越关机或重启- 需要开机自动恢复时,应使用
systemd、upstart或cron @reboot
手动 kill 进程
nohup 不会阻止手动终止。以下操作仍然有效:
kill PID发送SIGTERMkill -9 PID发送SIGKILLkillall command_name
所以 nohup 的保护范围仅限 SIGHUP。
nohup 失败时为什么看起来像“静默失败”
很多场景下,nohup 本身没有出错,真正退出的是它启动的命令。由于标准输出和标准错误被重定向,操作者断开连接后看不到即时反馈,就会误以为 nohup 静默失败。
常见原因包括:
- 命令本身启动即报错
- 配置文件错误
- 缺少依赖
- shell 脚本内部未处理错误,尤其启用了
set -e PATH环境比交互式 shell 更简化,导致子命令找不到- 运行过程中内存不足,被 OOM Killer 杀掉
- 磁盘空间耗尽
- 程序意外需要交互输入,而
nohup通常会让标准输入脱离终端 - 程序运行时权限不足
排查时优先检查日志文件,而不是先怀疑 nohup。
当 nohup.out 不可写时会怎样
如果没有显式重定向输出,nohup 会先尝试写入当前目录下的 nohup.out。失败后,再尝试写入 $HOME/nohup.out。
如果两处都不可写,可能出现两类结果:
nohup直接报错并退出,目标命令未启动- 目标命令启动了,但输出和错误无法正确写入,最终丢失
通常会在标准错误中看到无法打开 nohup.out 的提示。因此,生产环境里显式指定日志路径更稳妥,也更容易控制权限。
日志实践
指定清晰的日志文件名
避免长期依赖默认的 nohup.out。更合适的做法是使用描述性文件名,必要时带上日期:
nohup ./my_cmd > app_$(date +%F).log 2>&1 &
使用专门的日志目录
日志文件应存放在明确的位置,例如:
/var/log/my_app/- 项目目录下的
logs/
同时确认进程对目录和文件具有写权限。
让应用自己产生日志结构
nohup 只负责接住输出,日志质量取决于应用本身。理想日志应包含:
- 时间戳
- 日志级别,如
INFO、DEBUG、ERROR - 足够定位问题的上下文
处理日志轮转
nohup 不负责日志轮转。长时间运行的进程如果持续输出,日志会不断增长并占满磁盘。应通过以下方式处理:
- 应用内建日志轮转
- 使用
logrotate
日志查看
实时查看:
tail -f combined.log
按需搜索和检查:
less combined.log
grep ERROR combined.log
nohup、screen、tmux 的区别
三者都能帮助进程跨越终端断开,但定位不同。
| 工具 | 主要用途 | 是否可交互 | 是否支持会话恢复 | 复杂度 |
|---|---|---|---|---|
nohup |
让单个命令忽略 SIGHUP |
否 | 否 | 低 |
screen |
持久化终端会话,多窗口管理 | 是 | 是 | 中 |
tmux |
现代终端复用与会话管理 | 是 | 是 | 中到高 |
nohup
特点:
- 轻量
- 使用简单
- 适合单个、非交互、长时间运行的任务
- 启动后基本属于“放着跑”
限制:
- 无法重新进入会话
- 无多窗口能力
- 无窗格管理
- 仅处理
SIGHUP
screen
特点:
- 支持创建多个终端窗口
- 支持分离和重新附着
- 网络抖动后仍能保住会话
限制:
- 绑定键和窗口管理偏老派
- 学习成本高于
nohup
tmux
特点:
- 采用客户端-服务端模型
- 支持 session、window、pane
- 可定制性强
- 更适合复杂开发与运维工作流
- 脚本化能力强
限制:
- 老系统可能未预装
- 初始学习成本高于
nohup
如何选择
适合 nohup 的场景:
- 启动一个非交互脚本
- SSH 断开后任务仍需继续
- 只需要保活,不需要恢复现场
适合 tmux 或 screen 的场景:
- 需要持续观察实时输出
- 需要多窗口或多窗格
- 需要重新进入原会话继续操作
- 任务本身是交互式程序
常见命令示例
启动脚本并让其在后台持续运行
nohup ./script.sh > app.log 2>&1 &
分开记录输出和错误
nohup ./script.sh > app.log 2> app.err &
后台抓包
nohup sudo tcpdump -i any -nn -w /var/tmp/file.pcap -C 100 -W 50 "src x.x.x.x and dst y.y.y.y" &
查找相关进程:
pgrep -a tcpdump
或:
ps aux | grep tcpdump
终止进程:
sudo kill <PID>
处理管道命令时的写法
对包含管道、重定向的复杂命令,直接在命令最前面加 nohup 往往不够稳妥。应交给 shell 解释整条管道。例如:
nohup bash -c 'cat out.csv | cut -d "," -f3,4 | sed "s/,/\t/g" | sort -n -k 2 > out.txt' &
这样整条 pipeline 会作为一个 shell 命令执行,重定向和管道都能正确生效。
常见问题
nohup 到底做了什么
它让目标命令忽略 SIGHUP,从而在终端断开、注销或 shell 退出后继续运行。
nohup 一定要配合 & 吗
不一定。
nohup your_command:命令仍会忽略SIGHUP,但终端会被占用直到任务结束nohup your_command &:命令在后台运行,终端立即可继续使用
大多数场景都会加 &。
nohup 的输出去了哪里
默认行为:
- 先写当前目录下的
nohup.out - 当前目录不可写时,写入
$HOME/nohup.out
更常见也更推荐的方式是显式指定日志文件:
nohup ./my_script.sh > my_output.log 2> my_errors.log &
或者合并:
nohup ./my_script.sh > all_my_output.log 2>&1 &
nohup 和 tmux 的核心差别是什么
nohup 更接近一次性启动并放任其运行的工具,适合单条命令的保活;tmux 是完整的持久化交互会话系统,支持重新附着、窗口和窗格管理。
使用建议
如果目标只是让一个非交互命令在 SSH 断开后继续执行,nohup 足够直接:
nohup ./my_job.sh > job.log 2>&1 &
如果任务需要持续观察输出、保留交互现场、分多个窗口协作,使用 tmux 或 screen 更合理。
如果需求已经变成:
- 系统重启后自动恢复
- 失败自动拉起
- 需要标准化服务管理
- 需要统一日志和状态管理
则应切换到 systemd 服务,而不是继续扩展 nohup 的用途。
关于
关注我获取更多资讯