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

系统梳理 Linux nohup 的工作机制、输出重定向、后台运行、会话断开影响、常见失败原因及与 tmux、screen 的差异。

阅读时长: 7 分钟
共 3355字
作者: eimoon.com

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,再执行 bgdisown。不过对 SIGHUP 的免疫,nohup 本身已经提供。

nohup 与用户会话的关系

SSH 连接异常中断

网络中断或 SSH 客户端崩溃时,服务端的 SSH 守护进程通常会向登录 shell 发送 SIGHUP。shell 再把这个信号传给子进程。

普通进程会退出,使用 nohup 启动的进程会继续运行。输出会保存在 nohup.out 或自定义日志文件中。

这是 nohup 最典型的使用场景。

正常退出登录

执行 exitlogout 时,登录 shell 会结束,并向其子进程发送 SIGHUP。使用 nohup 启动的任务会忽略这个信号,因此在用户退出后仍可继续运行。

关闭终端模拟器窗口

如果是在本地终端中直接运行 nohup,关闭终端窗口通常会导致本地 shell 收到 SIGHUP,再传给其子进程。nohup 启动的进程会继续运行。

如果终端中承载的是 SSH 会话,关闭窗口等价于本地 SSH 客户端退出,远端行为与 SSH 中断相同。远程服务器上的 nohup 进程仍会继续运行。

进程失去原父进程后,其父进程 ID 可能变为 1init)或其他负责接管孤儿进程的系统进程。

会话超时或空闲超时

某些环境会通过 bashTMOUT 或 SSH 配置在长时间空闲后自动终止会话。底层机制通常仍涉及向 shell 发送 SIGHUP

这种情况下,nohup 启动的任务仍会继续运行。

系统关机或重启

这是 nohup 的边界之一。系统关机或重启时,操作系统会终止所有进程,常见顺序是先发 SIGTERM,超时后再发 SIGKILL

nohup 只忽略 SIGHUP,对 SIGTERMSIGKILL 不提供保护。因此:

  • nohup 无法让进程穿越关机或重启
  • 需要开机自动恢复时,应使用 systemdupstartcron @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 只负责接住输出,日志质量取决于应用本身。理想日志应包含:

  • 时间戳
  • 日志级别,如 INFODEBUGERROR
  • 足够定位问题的上下文

处理日志轮转

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 断开后任务仍需继续
  • 只需要保活,不需要恢复现场

适合 tmuxscreen 的场景:

  • 需要持续观察实时输出
  • 需要多窗口或多窗格
  • 需要重新进入原会话继续操作
  • 任务本身是交互式程序

常见命令示例

启动脚本并让其在后台持续运行

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 &

nohuptmux 的核心差别是什么

nohup 更接近一次性启动并放任其运行的工具,适合单条命令的保活;tmux 是完整的持久化交互会话系统,支持重新附着、窗口和窗格管理。

使用建议

如果目标只是让一个非交互命令在 SSH 断开后继续执行,nohup 足够直接:

nohup ./my_job.sh > job.log 2>&1 &

如果任务需要持续观察输出、保留交互现场、分多个窗口协作,使用 tmuxscreen 更合理。

如果需求已经变成:

  • 系统重启后自动恢复
  • 失败自动拉起
  • 需要标准化服务管理
  • 需要统一日志和状态管理

则应切换到 systemd 服务,而不是继续扩展 nohup 的用途。

关于

关注我获取更多资讯

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