Linux nohup 命令:退出登录后继续任务与日志管理
nohup 让启动的命令忽略终端断开时可能收到的挂断信号 SIGHUP。要在退出登录后继续运行非交互任务,通常还需使用后台符号 &,并明确重定向标准输入、输出和错误;它不能保证进程在所有退出策略下存活。
常用形式如下。worker.sh 必须是已准备、可执行并经过审核的脚本,日志目录必须可写;> 会清空已有同名日志,执行前先确认文件:
nohup ./worker.sh > worker.log 2>&1 < /dev/null &
nohup 不监控任务,也不在失败或重启后恢复它。长期服务需要配置启动、重启、日志与资源管理时,应考虑 systemd 等服务管理器。
nohup、后台符号和重定向分别做什么?
nohup 在运行命令前将 SIGHUP 设置为忽略。关闭终端或断开 SSH 时,shell 和相关进程可能收到该信号;忽略它有助于任务继续运行,但不改变其他信号、会话清理或系统关机的结果。
GNU Coreutils 官方手册源文件中的 nohup invocation 说明了信号、终端输入输出及退出状态。nohup 自身不会把命令放到后台,需由 shell 的 & 完成。
| 组成部分 | 作用 | 不提供的功能 |
|---|---|---|
| nohup | 启动时忽略 SIGHUP | 不会自动后台运行或重启 |
& |
让 shell 异步启动任务 | 本身不保证忽略 SIGHUP |
| 输入输出重定向 | 将标准流连接到指定文件或设备 | 不限制日志大小,也不自动轮转 |
基本语法与推荐写法
命令与参数
command 和 arg 是需要替换的占位内容:
nohup command [arg ...]
例如,当前目录已有可执行的 backup.sh 时:
nohup ./backup.sh
这会实际执行脚本,并保持前台运行,直到任务结束才返回提示符。脚本应具备正确的解释器、依赖、配置和输入数据;nohup 不会修复这些运行条件。
后台执行并保存日志
nohup ./backup.sh > backup.log 2>&1 < /dev/null &
> backup.log将标准输出写入文件,已有文件通常会先被截断。2>&1将标准错误复制到此时标准输出的去向,因此应放在输出文件重定向之后。< /dev/null将标准输入接到读出文件结束符 EOF 的设备;这不等于关闭文件描述符,也无法满足需要交互输入的程序。- 末尾的
&让 shell 不等待任务完成。
保留原日志并追加新输出时,改用双大于号:
nohup ./backup.sh >> backup.log 2>&1 < /dev/null &
每次启动前仍需检查是否已有同一任务。日志出现不代表任务成功;启动失败也可能只留下错误信息。
启动后立即记录 PID
进程 ID(PID)是进程编号,$! 给出 shell 最近启动的后台作业对应的 PID。简单命令可立即保存:
nohup ./backup.sh > backup.log 2>&1 < /dev/null &
job_pid=$!
printf '%s\n' "$job_pid" > backup.pid
PID 文件应位于仅任务管理者可写的可信目录。保存成功不证明程序已成功初始化;程序可能立即退出,也可能派生子进程。旧 PID 还可能被复用,因此停止任务前必须再次核对命令、所有者与启动时间。
标准输入输出与 nohup.out
标准输入
GNU nohup 发现标准输入连接终端时,会将其改接到不可读的输入源,这是 GNU 扩展。显式使用 < /dev/null 则提供可读但立即到 EOF 的输入,二者的错误行为并不完全相同。程序若必须持续读取数据,应提供真实输入文件,而不是依赖消失的终端。
标准输出
只有标准输出仍是终端时,GNU nohup 才按默认逻辑追加到当前目录的 nohup.out;无法写入时尝试 $HOME/nohup.out,两处均不可写则不执行命令。已明确重定向到文件时,不会因为使用 nohup 就额外创建默认输出文件。
多个任务共用 nohup.out 会混杂记录并持续增大。为每个任务指定日志位置与保留策略,更容易确认状态。shell 创建的自定义日志文件权限受相应创建规则影响,不应假定它自动获得 nohup 创建默认文件时的权限保护。
标准错误与重定向次序
标准错误仍连接终端时,GNU nohup 通常把它接到可能已重定向的标准输出;标准输出关闭时另有默认文件处理。明确写出 > file 2>&1 更易检查意图。反过来先写 2>&1 再重定向输出,连接结果可能不同,不能随意交换。
检查运行状态与日志
使用保存的 PID
job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
这是 Linux 常见 ps 格式:PID 是进程号,PPID 是父进程号,STAT 是状态,ETIME 对应的显示标题通常是 ELAPSED,表示已运行时长,CMD 是命令行。应确认这些信息与实际任务相符,必要时补查开始时间与所有者;不要把任意 PID 文件当作可信的停止指令。
按命令行搜索
pgrep -af 'backup.sh'
-f 匹配完整命令行,-a 显示 PID 和命令行。匹配表达式中的点号等还具有正则含义,也可能找到其他账号或名称相近的进程;结果只供进一步核实,不能直接批量终止。不同 ps、pgrep 实现的选项也应查本机文档。
持续查看日志
tail -f backup.log
tail -f 会显示末尾并跟随追加内容。按 Ctrl+C 停止前台 tail,通常不会停止另一个后台写日志任务。日志轮转时 -f 与 -F 的跟随对象不同,见 tail 的日志跟随方式。日志没有新增内容也不等于进程已停止。
如何停止 nohup 启动的任务?
核实后发送正常终止请求
以下示例包含真正的终止操作。先分别完成 PID、命令、所有者和启动时间的核对,确认它仍是本人的目标任务,再执行最后一行;不要整段盲目粘贴:
job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
kill "$job_pid"
kill 默认发送 SIGTERM,让程序有机会保存状态并清理资源,但程序可以捕获或忽略它。nohup 忽略 SIGHUP 并不意味着会忽略 SIGTERM。
复查进程与子进程
ps -p "$job_pid" -o pid,stat,etime,cmd
应按程序需要留出合理的清理时间,再核实是否退出。shell 脚本启动的子进程可能在父进程停止后留下;先检查进程树与进程组,优先采用应用提供的停止机制。僵尸状态也不代表程序仍在正常工作,需要由父进程回收。
最后才考虑强制终止
确实无法正常退出,且重新确认目标身份后,才使用:
kill -KILL "$job_pid"
SIGKILL 不能让程序执行自身清理步骤,可能造成未保存数据或状态不完整。只应针对已核实的目标,不要为了方便把范围扩大到所有匹配名称的进程。
管道、复合命令与输出缓冲
让一个 shell 解释完整管道
nohup sh -c 'producer | consumer' > pipeline.log 2>&1 < /dev/null &
producer 与 consumer 是需要替换的已准备程序。引号内的管道由新 sh 解释;nohup 只写在管道第一段前面,与将整个管道交给 nohup 启动的 shell,范围并不相同。子程序也可能自行调整信号处理,不能把整个进程树存活看作绝对保证。
不要将未经验证的输入拼入字符串。普通 sh 的管道通常取最后一段状态,前段失败可能被后段成功掩盖;需要准确判断时设计各阶段状态处理,并确认目标 shell 的功能。连接、后台与管道的区别可参考 英文 Bash 命令运算符说明,其中 Bash 特性不能默认套用到所有 sh。
日志延迟不一定是 nohup 故障
输出改接文件后,程序可能改变缓冲方式。先检查程序的日志刷新选项;兼容的 GNU 环境可请求行缓冲:
nohup stdbuf -oL -eL ./worker > worker.log 2>&1 < /dev/null &
worker 是另一个需要实际准备的可执行程序,不是系统自带命令。stdbuf 的 -oL、-eL 针对输出和错误流请求行缓冲;它要求程序使用 C FILE 流且不自行重新调整缓冲,对自有缓冲或不同 I/O 接口无效,也不是所有平台都安装。具体条件见同一官方 Coreutils 手册的 stdbuf invocation。
nohup 的边界与工具选择
不提供自动恢复与服务管理
- 不在系统重启后重新启动任务。
- 不在程序崩溃后自动重启,也不管理依赖启动顺序。
- 不提供 CPU、内存限制或健康监控。
- 不自动轮转、压缩、限额或删除日志。
- 不保留可以重新连接的交互终端会话。
会话管理器还可能在注销时终止整个会话范围的进程。例如 systemd-logind 的 KillUserProcesses 策略会按实际配置和例外项影响会话进程。忽略 SIGHUP 无法绕过这类终止。应由管理员按服务需求配置运行方式,而不是为保持一个任务随意弱化全局策略。
按任务选择工具
| 工具 | 适用情况 | 条件与特点 |
|---|---|---|
| nohup | 短期非交互批处理 | 简单执行,不监控或恢复 |
| systemd | 持续运行的服务 | 可配置启动、重启、依赖、日志与资源管理 |
| tmux(英文用法)、screen | 需要重新连接的交互操作 | 可分离和重连终端;服务器、会话及退出策略必须允许继续运行 |
| 调度器或任务队列 | 按时或周期执行任务 | 按工具能力安排执行、记录结果与处理失败 |
disown 与 nohup 的区别
Bash 的 disown 是处理现有后台作业的内建命令:默认可从作业表移除,-h 可标记相应作业,使 shell 不向它转发 SIGHUP。它不自动改接输入输出,也不能保证应对其他终止路径。nohup 则在启动命令时设置忽略 SIGHUP;不同 shell 的 disown 选项和行为可能不同,脚本应确认实际 shell。
执行前检查哪些条件?
- 路径和依赖:确定工作目录、解释器、程序和配置文件,必要时使用绝对路径。
- 日志与权限:确认覆盖还是追加、目录可写、敏感信息不被记录,设置合适的访问权限。
- 容量:配置程序日志保留或 logrotate;运行中的文件轮转方式必须与程序兼容。
- 重复启动:确认并发是否安全,必要时采用程序的单实例机制或经过设计的锁。
- 环境:nohup 不会自动建立登录环境;明确 PATH、locale、工作目录及任务需要的变量。
- 凭据:不要将密码和令牌放在可能被进程列表或历史记录暴露的参数中,采用程序支持的安全凭据方式。
- 状态与退出:立即记录 PID,同时准备结果检查和正常停止方法,包含剩余子进程的处理。
常见问题
关闭 SSH 窗口后一定继续运行吗?
不一定。nohup 设置忽略 SIGHUP,但程序可修改信号处理、继续使用终端,系统也可按会话策略或其他信号终止它。分离标准流后仍应验证实际运行条件,关键长期任务应采用合适的服务管理方式。
如何避免创建 nohup.out?
显式指定输出与错误的目的地。只有无需任何诊断记录时才考虑全部丢弃:
nohup ./worker > /dev/null 2>&1 < /dev/null &
丢弃输出不会使失败消失,也会减少排查依据;一般运行任务更适合独立日志。
为什么新登录后 jobs 看不到原任务?
jobs 只显示当前 shell 管理的作业。新 shell 不继承旧 shell 的作业表。通过可信 PID、进程信息和任务结果检查,或查询对应服务状态。
退出状态如何判断?
GNU nohup 自身失败通常为 125,找到但无法执行命令为 126,找不到命令为 127;其他情况返回命令状态。设置 POSIXLY_CORRECT 时,自身错误使用 127。后台启动后立即读取 $? 只反映异步启动语句,不能说明最终任务成功;原 shell 仍在且任务是其子作业时可用 wait 等待并取得状态,重新登录的 shell 不能直接 wait 旧 shell 的任意进程。
操作要点
nohup 负责忽略 SIGHUP,& 负责后台执行,重定向负责标准流去向。运行已准备的任务时,明确日志覆盖或追加、隔离终端输入输出、保存并核实 PID,再检查实际结果。需要重启恢复、长期监控或完整交互会话时,按任务选择服务管理器或终端复用工具。




