Linux定时任务精讲:at与crontab的区别及运维实战

很多人刚接触 Linux 系统时,都会遇到一个困惑:想定时跑个脚本,身边人一会儿说用at,一会儿又说用crontab,打开配置文件一看,五颗星加一串命令,脑子直接浆糊。其实这两个命令是互补的,一个管“一次性”,一个管“周期性”,搞懂区分逻辑再上手,一点都不难。

这篇东西我按实际运维中会遇到的思路来写:先讲清楚两个工具的定位差异,再分别把at和crontab的关键参数、配置方式、日志排错讲透,最后给出一套完整的定时任务落地建议。无论你是刚入手 Linux 的开发者,还是被服务器上各种定时脚本折腾过的运维,都应该能从里面找到可以直接用的东西。

1. 两个命令解决的是两件事,别混着用

先说一个很多教程没讲透的点:at和crontab虽然都叫定时任务,但它们的业务场景完全不同。搞混了会出现一种很尴尬的情况——你明明用at提交了一个每天凌晨三点要执行的任务,结果第二天发现它只跑了一次就再无下文,因为at本来就不管重复执行。

at处理的是一次性任务。比如你想今晚 23:30 给数据库做一次临时备份,或者两个小时后发一封测试邮件,这种“只执行一次、到点就完事”的需求,就是at的本职工作。它的名字本身就很直白,英文里 at 表示时间点,它强调的是“在某个具体时刻做这件事”。

crontab处理的是周期性任务。它来自 cron 这个单词,跟“时间表”一个意思。你想让系统每天凌晨备份、每周日凌晨清理日志、每分钟检查一次服务存活状态,这些需要按秒级、分级、天级、周级不断重复的任务,只能用crontab来定义。它包含六个字段,前五个字段组合出一个周期性的时间表达式,最后一个字段是具体要执行的命令。

有一个更直观的方法帮你记忆这两个工具的分工:把服务器想象成一个值班室。at相当于在值班日志上写一条“今晚八点去机房巡检”,只提醒一次;crontab相当于写进值班制度里的“每天八点准时巡检”,只要制度不改,它就一直在。

知道了两者的边界,再来看具体操作。命令本身非常简单,但真正容易翻车的是一些隐藏的权限、路径、日志细节。下面我拆开讲。

2. at 命令的核心实操与避坑要点

2.1 基本语法与常用写法

at命令的用法很简单:

at [选项] 时间

先输入命令指定时间,回车后会进入一个交互式输入界面,你输入要执行的命令序列,最后按Ctrl + D提交。也可以直接配合echo或是用管道直接把命令传给它,这样更适合在脚本里使用。

echo "mysqldump -u root test_db > /tmp/backup.sql" | at 23:30

时间部分支持几种很贴近人类表达习惯的写法,不用计算复杂的日期格式:

  • at 23:30(今天 23:30,如果时间已经过了,则顺延到明天)
  • at 4:00 2026-01-20(指定具体日期)
  • at now + 5 minutes(5 分钟后执行)
  • at noon、at teatime(下午茶时间 16:00)、at midnight(午夜 00:00)
  • at 9:00 AM tomorrow(明天早上九点)

这里有一个我刚上手时容易搞错的地方:at的时间是执行命令的瞬间,而系统里如果开了多用户环境,at作业执行时不会加载你的交互式 shell 环境。也就是说,echo $HOME这类变量和你手动在终端里敲出来的可能完全不一致,所以脚本想依赖环境变量的话,要么写绝对路径,要么在命令前先source /etc/profile。

2.2 管理已经提交的任务

提交之后发现写错了,或者想看看当前有哪些任务在排队,用这几个命令:

atq # 列出当前用户的at任务列表 atrm 5 # 删除编号为5的at任务

atq输出的编号就是任务的 ID,atrm后面跟编号就能删掉对应任务。要注意,默认情况下管理员可查看和删除所有用户的任务,但普通用户只能看自己的。

任务的输出默认会通过邮件发给提交任务的用户,邮件这个功能在很多精简环境里没有配置,于是输出就静默丢失了。这个坑非常典型,第一次用at提交任务的初学者经常发现自己脚本跑完没有任何反馈,还以为是没执行。可以用重定向把输出写到文件里:

echo "date >> /tmp/at_test.log 2>&1" | at now + 1 minute

比如上面这个任务,就把执行结果统一追加到/tmp/at_test.log里,方便事后去查。

2.3 权限控制的细节

at的权限控制不是看用户组,而是看两个文件:

  • /etc/at.allow:白名单,文件里列出允许使用at的用户,一行一个。
  • /etc/at.deny:黑名单,阻止某些用户使用at。

这两个文件的优先级是:如果at.allow存在,则只有里面的用户能使用at,at.deny直接被忽略;如果at.allow不存在,才看at.deny,不在黑名单里的用户都能用;如果两个文件都不存在,仅 root 能使用at。

几个系统对这个文件的默认处理可能不同,但逻辑都是一致的。运营团队共用服务器的时候,建议显式创建at.allow文件,避免每个人都随意提交任务,省得排查问题时分不清是谁的锅。

3. crontab 的核心实操与时间表达式解析

3.1 五分钟理解五颗星的时间表达式

crontab的配置格式可以简化为6个字段,但实际上常见写法是5个时间字段加1个命令字段。为了好记忆,可以用这句话来记:“分 时 日 月 周”。每颗星依次对应的是,命令会在被标记的任意时刻执行。

整个格式长这样:

分 时 日 月 周 要执行的命令

举几个最常用的例子:

30 3 * * * /usr/bin/backup.sh # 每天凌晨3点30分执行 */5 * * * * /usr/bin/check.sh # 每5分钟执行一次 0 2 * * 1 /usr/bin/cleanup.sh # 每周一凌晨2点执行 0 4 1 * * /usr/bin/report.sh # 每月1号凌晨4点执行 @reboot /usr/bin/start_service.sh # 系统重启后执行

初次上手时最容易犯的错误,是把时间顺序反了。有人会下意识把30 3当成 “3点30分”,这没错;但一写成任务就翻车,比如要写“每3小时执行一次”,居然写成0 */3 * * *,然后漏了最前面的分字段只写*/3 * * * *,变成每3分钟跑一次,等着服务器被自己的脚本打崩。

注意*的含义是“每一个”,*/是“每隔多少”的意思。*/5在分字段里表示每5分钟一次,在时字段里表示每5小时一次,位置不同含义不同。

crontab里的周和日的优先级也比较特殊,当“日”和“周”同时设定时,两个条件满足任意一个命令就会执行。如果写0 0 15 * 5表示“每月15号且同时是周五”,严格说实际效果是“每月15号或在周五执行”,很多人研究半天为什么坏是坏在这里。

3.2 配置与管理的正确姿势

有两个容易混的命令:crontab -e和直接编辑/etc/crontab。如果你只想管理自己用户的任务,用前者;如果想编辑系统级任务,或者想在里面额外指定“以某个用户身份执行”,一般用后者。

crontab -e编辑的是当前用户的任务文件,保存后立刻生效,不需要重启任何服务。系统级别的任务文件格式会多一个用户字段:

0 3 * * * root /usr/local/bin/backup.sh

这个表格的意思就是,每天凌晨3点,用root身份去执行/usr/local/bin/backup.sh。普通用户没有权限直接改/etc/crontab,运维在管理多用户服务器时会把所有系统级任务集中放这里,方便审计。

查看当前用户已有任务:

crontab -l

删除当前用户的所有任务:

crontab -r

提示:crontab -r不加任何提示直接清空,没有二次确认,手滑就没了。运维界有一条铁律,在执行这个命令前先crontab -l看一眼内容并备份。我自己通常执行crontab -l > crontab_backup.txt,给自己留条后路。

3.3 环境变量与路径的坑

crontab执行任务时,环境变量跟你手动终端登录时完全不同。它会用默认的PATH,基本就是/usr/bin:/bin,而你装在/usr/local/bin里的脚本命令,它八成都找不到。

一个典型的故障场景是:你手动执行备份脚本一切正常,但定时任务一跑就报mysqldump: command not found。原因很简单,mysqldump装在/usr/local/mysql/bin下面,cron 的 PATH 里没有这个目录。

常规的解法有两种。第一种是在脚本头部显式 export 环境变量与 PATH;第二种是把所有外部命令写成绝对路径。我自己的项目里基本是混着用,脚本开头写成:

#!/bin/bash export PATH="/usr/local/bin:/usr/local/mysql/bin:/usr/bin:/bin:$PATH"

把需要用的工具路径都加进去,后续命令不用每个都写全路径,代码干净又不容易踩坑。

还有一个%号的问题。crontab里百分号是有特殊含义的,在命令里出现%会被当作输入换行符,传给命令的时候直接截断。如果你要在脚本里用date +%Y%m%d这种写法,必须转义:

0 2 * * * /usr/bin/backup.sh >> /tmp/backup_$(date +\%Y\%m\%d).log 2>&1

这里我把整条命令塞进了一个外层带转义的形式里,实际处理时注意每个%都要加反斜杠。

4. 实战:组合 at 与 crontab 构建一套可靠的定时运维体系

4.1 日常备份的定时策略设计

一个典型的项目,需要做数据库每日备份、日志清理、临时任务提交三个层面的事。我用一个完全虚构但很有代表性的模拟项目 X 来说明整套配置长什么样。

每日备份用crontab处理:

0 1 * * * /opt/script/backup_db.sh >> /var/log/backup_db.log 2>&1 30 1 * * * find /data/backup -mtime +7 -name "*.sql.gz" -exec rm -f {} \;

第一条每天凌晨1点整执行数据库备份脚本;第二条在备份完成后30分钟清理7天以前的备份压缩包,避免磁盘被撑爆。日志和数据文件都重定向到了明确的路径,排错时直接去翻文件,不必去系统邮件目录里找。

某些临时性的运维动作,比如今晚2点半要升级某个模块,但升级前希望先做一个独立快照,这时直接用at更合适:

echo "/opt/script/snapshot.sh" | at 2:30 2026-01-20

这个任务只执行一次,不污染crontab里的规矩模板,又能在指定时间自动触发。可以说,crontab管日常、at管临时,这两个工具配合使用才能覆盖一个运维场景里所有的定时需求。

4.2 防止脚本重复运行

定时任务跑多了,会碰到一种很典型的故障:上一个周期脚本还没结束,下一个周期的又启动了,两边同时在操作同一批文件,直接数据异常。比如备份脚本执行时长超过5分钟,但你的crontab是每5分钟执行一次,就会发生重叠。

可靠的解决办法是在脚本里加锁。我用的是最简单也最实用的文件锁方案:

#!/bin/bash LOCK_FILE="/tmp/backup.lock" exec 9>"$LOCK_FILE" if ! flock -n 9; then echo "Another backup process is running, exit." exit 1 fi # 正式任务逻辑 /usr/bin/mysqldump ...

flock是系统自带的锁命令,-n参数表示非阻塞,如果拿不到锁就直接退出。这个方案比pidof判断进程号更稳,因为哪怕脚本崩了锁文件还在,老进程没结束前新的永远进不来。

4.3 日志集中与轮转

任务一多,日志管理就成了问题。我给每个任务单独建了日志目录,并用logrotate做日志轮转,避免单个日志文件无限膨胀。

/etc/logrotate.d/project配置示例:

/var/log/project/*.log { daily rotate 30 compress missingok notifempty }

意思就是/var/log/project目录下的所有日志每天轮转一次,保留最近30份,旧日志自动压缩。配置完成后定期手动执行logrotate -f验证是否生效,不要真的等一个月后再去检查,那时日志可能已经几十 GB 了。

5. 常见故障速查与排错指南

定时任务不怕报错,怕的是报错信息去了你找不见的地方。以下是我实操中遇到频率最高的几类问题,整理成表方便直接对着查:

问题现象可能原因排查方法
任务没执行,但没有错误输出cron服务没有启动systemctl status crond查看服务状态,服务挂了自然啥都不跑
脚本执行了但命令找不到cron 的 PATH 不完整在脚本头部 export PATH,或命令写绝对路径
任务每天重复执行多次时间表达式写反重新核对分、时、日、月、周的顺序
输出日志是空的输出未重定向,被系统邮件吞了显式加>> /var/log/xxx.log 2>&1
at提交后系统报错时间格式不受支持用now + 1 minutes这类相对时间最稳
多个脚本互相覆盖同一文件无锁机制,任务重叠运行在脚本内加flock互斥锁
任务时区不对系统时区不是本地时区timedatectl status查看,必要时改/etc/localtime

日志排查也是个重要技能。大部分 Linux 发行版,cron的执行记录会写在/var/log/cron里。每次任务执行都会留下一条记录,包括执行时间、执行用户和具体命令。前端看不到的问题去日志里一翻就现原形。如果配置了系统日志,也可以直接查journalctl -u crond。

我自己排查定时任务故障的固定流程是:先查 cron 服务状态,再查 /var/log/cron 日志,最后手动复制命令行执行一遍。这三步能解决九成问题。如果三步都走完仍然没头绪,再考虑脚本内部逻辑问题,比如权限不足、磁盘满了、锁没有释放。

举个例子,某次我维护的项目连续三天凌晨没有生成备份文件。按流程第一步服务状态正常,第二步去/var/log/cron看到任务“确实执行了”,第三步手动跑脚本本身也成功。那问题出在哪?最后翻到脚本内部才发现它依赖一个环境变量,而这个变量只在登录 shell 里存在。cron 启动脚本时没加载~/.bashrc,自然拿不到。把环境变量定义直接挪进脚本开头,立刻恢复。

这种环境差异导致的诡异故障,我觉得是新手最容易栽的地方,所以特意建议所有写定时任务的开发者,把脚本写得尽量“自包含”:环境变量自己设,路径写绝对,依赖哪几个文件提前声明,不要让脚本去猜运行环境。

6. 时区、权限与多用户协作的进阶经验

多用户服务器上用定时任务,还有一个很容易被忽视的权限协作问题。不加限制时所有用户都能用crontab -e建自己的任务,十几个人的团队就有十几个任务集合。看似互不干扰,实际所有任务都写进同一个 cron 机制里,一旦某个任务失控,整个系统的负载都会被打高。

我比较推荐的原则是:普通用户尽量不使用个人 crontab,而是把需要周期执行的任务统一收敛到专门的运维用户或使用系统级/etc/crontab统一管理,并在每行注明任务用途与负责人。集中化管理的优势在排查问题时最直观——打开一个文件就能看到全貌,而不是挨个用户crontab -l。

at命令的权限控制相对简单,只要你把普通用户排除在at.allow之外,他们就不能提交一次性任务。这在生产环境里是合理限制,避免某位同事随手提交个“现在 + 2 分钟重启服务”的任务,半夜把整个业务弄断。

时区问题容易被忽视但极其致命。如果服务器时间不同步,比如一台机器时区是 UTC 而应用时区是东八区,配置里写的凌晨2点实际是本地时间上午10点。数据库备份从凌晨2点变成上午10点,刚好撞上业务高峰,磁盘 IO 被打满,接口立刻变慢。

检查时区最直接的方式:

timedatectl

输出里的Time zone字段就是当前时区。如果不对,直接改成需要的时区:

timedatectl set-timezone Asia/Shanghai

改完时区以后再测试定时任务,确保时间符合预期。比这更深一层是时间同步问题,服务器如果没配 NTP,时间漂移几十分钟也是常有的事,定时任务全部不准。这一步在很多系统镜像里是默认配好的,但自己搭的环境一定要检查一下。

7. 最后再给几条实在建议

在我维护过的所有项目里,定时任务从来不是“写完就行”的东西,它需要整体设计,包括日志怎么收、失败怎么告警、脚本之间怎么避免冲突。三个经验最后分享一下。

第一,所有任务输出必须落盘。不让 cron 把输出发到邮箱,而是每条任务都显式指定>> /var/log/xxx.log 2>&1。落盘之后可以配合logrotate做轮转,出问题时翻日志效率高得多。

第二,脚本加锁比加判断好。进程重叠是线上事故高发点,用flock或简单的文件锁在脚本入口挡住并发执行,比脚本内部用临时变量判断慎靠谱得多,因为锁文件天然是崩溃安全的。

第三,修改配置前先备份,改完立即验证。crontab -l先看现状,改动之后用crontab -l确认新配置确实写入,再用at now + 1 minute或者把时间临时改成下一分钟验证一次。生产环境里不是每次都有机会等一个周期跑完再确认,能提前验证就别干等。

定时任务的问题往往不是出在格式上,而是出在环境、时长、权限这些软性因素里。把这两条命令吃透,配合一套自己的排错流程,基本就能覆盖日常运维中九成以上的定时调度需求。

相关新闻

OTN光传送网实战指南:从帧结构、保护倒换到设备选型与故障排查

OTN光传送网实战指南:从帧结构、保护倒换到设备选型与故障排查

1. 从一个机房的真实困境说起:为什么需要OTN很多刚接触传输网络的朋友会有一个疑问:现在光纤资源这么丰富,核心交换机、路由器性能这么强,为什么还要专门搞一套OTN光传送网?我最初也有同样的困惑,直到有一次…

2026/10/21 4:18:43 阅读更多 →
阿里云ECS上10分钟搭建OpenClaw:让AI成为能干活、能定时执行任务的数字员工

阿里云ECS上10分钟搭建OpenClaw:让AI成为能干活、能定时执行任务的数字员工

先说个结论:这项目没你想的那么神秘。我最早看到“OpenClaw(Clawdbot)”这个名字时,第一反应是又一个大模型套壳机器人框架,无非是接个聊天窗口、问一句答一句那种。后来发现我错了——它真正值钱的地方在于“让AI动手…

2026/10/21 4:18:43 阅读更多 →
多模态大模型驱动的全流程AI自动化架构设计与实践

多模态大模型驱动的全流程AI自动化架构设计与实践

做AI自动化落地有一段时间了,从最早的单模型接口调用,到后来尝试用大模型做Agent,再到把整套流程串起来跑成真正能用的系统,每一步都踩了不少坑。今天想聊聊我最近搭建的一个叫“玄晶引擎”的架构——一个基于多模态大模型的全流程…

2026/10/21 4:18:43 阅读更多 →

最新新闻

IDEA多模块工程:Java与Python自动化测试框架统一管理实战

IDEA多模块工程:Java与Python自动化测试框架统一管理实战

讲个真实场景。我接手某个自动化测试框架改造的时候,团队同时维护着两套代码:Java 这边用 TestNG 写接口用例已经跑了两三年,Python 那边用 pytest 处理数据校验和运维脚本也形成了规模。每次发布前,负责 Java 的同学跑完要导一份…

2026/10/21 5:01:00 阅读更多 →
STM32+红外模块控制格力空调:从硬件到代码的完整方案

STM32+红外模块控制格力空调:从硬件到代码的完整方案

简介:这份资源面向嵌入式开发初学者与智能家居DIY爱好者,提供基于STM32微控制器驱动红外模块控制格力空调的完整工程实践。内容围绕STM32的GPIO推挽输出、定时器PWM波形生成、NEC红外编码与解码、协议适配及示波器调试等关键环节展开,帮助读者…

2026/10/21 5:01:00 阅读更多 →
rea监控分析组件:从统一事件模型到告警收敛的实战指南

rea监控分析组件:从统一事件模型到告警收敛的实战指南

深夜两点十七分,我盯着屏幕上滚动的告警流,第无数次按下刷新键。这不是什么特殊的日子,只是一个普通的线上值班夜。系统表现得很“正常”——业务指标平稳,日志没有报错,可监控大盘上那条细小的毛刺,却让我…

2026/10/21 5:01:00 阅读更多 →
5G接入控制机制详解:从统一接入控制到切片感知的参数配置与调优

5G接入控制机制详解:从统一接入控制到切片感知的参数配置与调优

1. 5G接入控制到底在控制什么第一次接触5G接入控制这个概念,很多人会把它和“能不能连上基站”混为一谈。实际上,接入控制要解决的问题比“连不连得上”精细得多。它管的是:在什么条件下允许一个终端发起接入、以什么身份接入、接入后能占用多…

2026/10/21 5:01:00 阅读更多 →
零基础转岗网络安全?十个简单实操任务助你快速入门

零基础转岗网络安全?十个简单实操任务助你快速入门

转岗网安,零基础,十个简单教程,避开复杂理论,轻松掌握核心技能——这话听起来很营销,但我可以负责任地告诉你,它确实是可以成立的。前提只有一条:你找对入门方向。很多人劝退转岗网安&#xff0…

2026/10/21 5:01:00 阅读更多 →
资源效率分析器REA落地实践:从需求拆解到优化建议生成

资源效率分析器REA落地实践:从需求拆解到优化建议生成

说实话,第一次见到“REA”这三个字母时,我以为是某个新框架的缩写。等到需求文档推到我面前,才发现这是一个极简到极致的项目代号,背后要做的是一个资源效率分析器(Resource Efficiency Analyzer)。当时团队…

2026/10/21 4:59:59 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →