Linux nohup 命令(实战指南)

Linux nohup 命令:让后台任务“不怕断网”运行的秘诀

你有没有遇到过这样的情况?在远程服务器上运行一个脚本,比如一个数据处理程序或者一个 Python 服务,刚运行一会儿,突然因为网络波动、SSH 连接断开,程序就直接终止了。你再登录上去一看,任务不见了,数据也还没处理完,心里那个急啊。

这背后的原因,其实和 Linux 系统对进程信号的处理机制有关。当你通过 SSH 登录服务器执行命令时,这个命令就运行在一个终端会话中。一旦你退出登录,系统会向该会话下的所有子进程发送 SIGHUP 信号,也就是“挂起”信号,导致这些进程被强制终止。

nohup 命令,正是为了解决这个问题而生的。它的全称是 "no hang up",顾名思义,就是“不怕挂断”。它能让你启动的进程在你退出 SSH 后依然持续运行,真正实现“后台守护”。


什么是 Linux nohup 命令?

nohup 是 Linux 系统中一个内置命令,用于执行命令并忽略 SIGHUP 信号。这意味着即使你关闭终端或断开 SSH 连接,被 nohup 启动的程序也不会收到“挂断”信号,从而不会被终止。

想象一下,你把一个任务交给一个“不会离岗”的员工。这个员工会一直工作,哪怕你关掉办公室的门,他也不会因为“门关了”就走人。nohup 就是这个“不会离岗”的机制。

基本语法

nohup command [arguments] &
  • command:你想要运行的命令或脚本,比如 python app.pyjava -jar myapp.jar
  • [arguments]:传递给命令的参数。
  • &:表示将任务放到后台运行,让你可以继续输入其他命令。
  • nohup 会自动将命令的标准输出(stdout)和标准错误(stderr)重定向到一个名为 nohup.out 的文件中(除非你手动指定)。

使用 nohup 的基本示例

下面是一个完整的使用案例,帮助你快速上手。

示例 1:运行一个 Python 脚本

import time

print("开始执行任务...")
for i in range(10):
    print(f"第 {i + 1} 次循环,当前时间:{time.strftime('%H:%M:%S')}")
    time.sleep(2)

print("任务执行完成!")

现在我们用 nohup 来运行它:

nohup python app.py &

执行说明:

  • python app.py:运行 Python 脚本。
  • &:将任务放入后台,你不需要等待它结束。
  • nohup:自动忽略 SIGHUP 信号,防止断开连接时被终止。
  • 输出会自动保存到 nohup.out 文件中(当前目录下)。

⚠️ 注意:如果当前目录没有写权限,nohup.out 无法创建,命令会报错。建议使用绝对路径,比如 nohup python /home/user/app.py &


示例 2:运行 Java 应用

假设你有一个 Spring Boot 项目打包成 JAR 文件:

nohup java -jar myapp.jar --spring.profiles.active=prod &
  • java -jar myapp.jar:启动 Java 应用。
  • --spring.profiles.active=prod:指定运行环境为生产模式。
  • &:后台运行。
  • nohup:确保断开连接后服务不崩溃。

这个命令非常适合部署微服务或 Web 应用,即使你关闭 SSH 客户端,服务依然在运行。


nohup 输出重定向:让日志更清晰

默认情况下,nohup 会把标准输出和错误输出都写入当前目录的 nohup.out 文件。但如果你有多个任务,或者希望日志分类管理,可以手动重定向。

自定义输出文件

nohup python app.py > app.log 2>&1 &

命令解释:

  • > app.log:将标准输出(stdout)重定向到 app.log 文件。
  • 2>&1:将标准错误(stderr)也重定向到 stdout,也就是一起写入 app.log
  • &:后台运行。

这样,所有日志都会集中在 app.log 中,便于排查问题。

重定向到 /dev/null(丢弃输出)

如果你不想保存任何日志,可以这样做:

nohup python app.py > /dev/null 2>&1 &
  • /dev/null 是 Linux 中的“黑洞”,所有写入它的内容都会被丢弃。
  • 适合那些不需要日志记录的后台任务,比如定时任务或监控脚本。

查看和管理后台任务

启动了 nohup 任务后,你可能想知道它还在不在运行。这时候,jobsps 命令就派上用场了。

查看后台任务(jobs 命令)

jobs

输出示例:

[1]+  Running                 nohup python app.py &
  • [1]:任务编号。
  • Running:表示任务正在运行。
  • nohup python app.py &:任务命令。

查看进程列表(ps 命令)

ps aux | grep python
  • ps aux:列出系统中所有进程。
  • grep python:过滤出包含 "python" 的进程。

输出中你会看到类似:

user   12345  0.1  1.2  54321  23456 pts/0    S+   10:30   0:01 python app.py

这个进程 ID(PID)是 12345,你可以用它来终止任务。


终止 nohup 运行的任务

有时候你可能需要手动停止一个 nohup 运行的程序,比如更新代码或修复 bug。

使用 kill 命令

kill 12345
  • 12345 是你通过 ps 命令查到的进程 ID(PID)。
  • 这个命令会发送 SIGTERM 信号,请求程序优雅退出。

如果程序没有响应,可以强制终止:

kill -9 12345
  • -9 表示发送 SIGKILL 信号,强制终止,无法被捕获或忽略。

💡 提示:建议先用 kill,再用 kill -9,避免数据丢失。


实际场景:部署一个持续运行的爬虫

假设你要部署一个 Python 爬虫,每天定时抓取网页数据。你可以写一个简单的脚本,并用 nohup 启动。

爬虫脚本(spider.py)

import requests
import time
import logging

logging.basicConfig(filename='spider.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def crawl_website():
    url = "https://httpbin.org/get"
    try:
        response = requests.get(url, timeout=10)
        logging.info(f"成功获取数据,状态码:{response.status_code}")
    except Exception as e:
        logging.error(f"请求失败:{e}")

if __name__ == "__main__":
    while True:
        crawl_website()
        time.sleep(300)  # 每 5 分钟运行一次

启动命令

nohup python spider.py > spider.log 2>&1 &
  • 每 5 分钟运行一次,日志保存在 spider.log
  • 即使你断开 SSH,爬虫依然持续运行。

你还可以配合 cron 定时任务,实现每天自动启动,真正做到“无人值守”。


常见问题与注意事项

问题 解决方法
nohup.out 文件无法创建 检查当前目录是否有写权限,使用绝对路径
任务运行后输出为空 检查是否重定向了输出,用 tail -f nohup.out 查看实时输出
无法终止任务 使用 `ps aux
多个 nohup 任务冲突 建议为每个任务使用不同的日志文件名,避免覆盖

总结

Linux nohup 命令 是一个简单却非常实用的工具,尤其适合在远程服务器上运行长期任务。它通过忽略 SIGHUP 信号,让你的程序“不怕断网”,真正实现“后台守护”。

无论是部署 Web 服务、运行数据处理脚本,还是定时执行爬虫任务,nohup 都能为你省去很多麻烦。配合 &> /dev/null 2>&1pskill 等命令,你完全可以构建一个稳定、可管理的后台任务系统。

记住:一个 nohup 命令,让你的程序不再“随你而去”。

掌握它,是你从初级开发者迈向中级运维能力的重要一步。现在就去试试吧,让你的任务“安心”运行。