Linux 中如何使用 nohup:断开终端后继续运行进程

系统梳理 Linux nohup 的工作机制、输出重定向、后台运行、会话断开影响、常见失败原因及与 tmux、screen 的差异。在 Linux 中,长时间运行的任务经常会遇到同一个问题:终端关闭、SSH 断开、用户退出登录后,任务也跟着结束。nohup 提供了一种直接的处理方式,它让目标进程忽略 SIGHUP 信。

在 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 发送 SIGTERM
  • kill -9 PID 发送 SIGKILL
  • killall 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 的输出去了哪里

默认行为:

  1. 先写当前目录下的 nohup.out
  2. 当前目录不可写时,写入 $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 的用途。

关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号
使用 Hugo 构建
主题 Stack 由 Jimmy 设计