☰
Shell脚本+FFmpeg:打造智慧园区视频监控自动化实践
2026/10/21 4:18:47 网站建设 项目流程

1. 需求分析:智慧园区里到底需要脚本做什么

接手智慧园区项目之后,你会发现一个很现实的问题:FFmpeg 本身是个极其强大的命令行工具,但命令行是要人去敲的。园区里几十上百路摄像头,不可能每路都手动拉流转码,更不可能半夜两点爬起来处理一路离线告警。这时候 Shell 脚本的价值就出来了,它是把 FFmpeg 从“工具”变成“服务”的那层胶水。

我参与的这个某智慧园区项目,核心场景大概分三类:

第一类是视频巡检。园区周界、地库、楼栋大堂的摄像头需要定时抓图存档,比如每 15 分钟抓一张,用于后续异常追溯。第二类是录像归档。部分重点区域需要把 RTSP 流周期性地转成 MP4 存到 NAS,保留 30 天滚动覆盖。第三类是异常事件的快速取证。比如门禁告警触发后,需要立刻回拉前 5 分钟的录像切片,交到物业或安防人员手里。

这三类需求有个共同点:全都是重复性的、定时触发的、可以用参数区分场景的任务。这恰恰就是 Shell 脚本的主场。它不需要复杂的业务逻辑,只需要做好三件事:调起 FFmpeg、判断执行结果、把输出文件按规则命名归档。剩下的什么并发控制、异常告警、日志轮转,都是在基础骨架上的加固。

很多人一开始会纠结:都用 Python 不就行了吗?诚然,Python 做视频处理的后处理、AI 分析确实更顺手,但纯采集、转码、归档这条链路,Shell 是更轻的选择。它不需要虚拟环境、不需要依赖管理,服务器上只要有 FFmpeg 和 cron,脚本一丢就能跑。对于维护园区的运维同事来说,一条bash check_ffmpeg.sh远比调试pip install来得省心。

另外还要强调一点:Shell 脚本这层是“无状态”的。每次执行都是独立的进程,失败了也不会影响下一次。这个特性在园区这种需要常年 7x24 小时运转的场景里,比什么都重要。脚本挂了,大不了下个周期再跑;但业务服务挂了,可能整个监控中心就哑了。

所以,这整套自动化脚本的设计目标非常明确:让 FFmpeg 在园区场景里变成一个“无人值守但不失控”的执行单元。

2. 基础准备:环境、目录需求和第一条测试命令

写脚本之前,先把地基打好。我这里说的环境准备,不是只装一个 FFmpeg 那么简单,而是要明确你所在服务器的定位。

先看操作系统。这类脚本基本都跑在 Linux 上,我这边用的是一台 CentOS 7.9 的服务器,配置不高,4 核 8G,专门用来做视频采集转发。如果你用的是 Debian/Ubuntu 也没关系,核心命令都是一样的,只有软件包管理器不同。

再看 FFmpeg 版本。这里必须提醒一句:优先用官方静态编译版本,别用系统自带的旧版。CentOS 7 自带的 FFmpeg 版本很旧,对 H.265、HEVC 的支持很差,而且编译参数里缺了一大堆解码器。我是从 FFmpeg 官网下载了 static build,解压到/usr/local/ffmpeg,然后软链到/usr/local/bin/ffmpeg。这样版本可控,换机器也方便。

要确认编译参数是否满足需要,执行:

ffmpeg -version ffmpeg -protocols | grep rtsp ffmpeg -codecs | grep h264

重点看有没有--enable-libx264、--enable-gpl,以及网络协议里是否包含rtsp。如果用的是静态版,这些通常都全。我当时踩过一个坑:某台服务器上系统自带的 FFmpeg 只有-f mpegts能用,RTSP 转封装直接报Method DESCRIBE failed: 401 Unauthorized,后来换了静态版才解决。

然后是目录结构的规划。脚本运行最忌“文件到处都是”。我习惯用下面这套目录布局:

/opt/ffmpeg_scripts/ ├── bin/ # 脚本统一存放 ├── logs/ # 运行日志 ├── tmp/ # 临时文件、切片缓存 ├── capture/ # 定时抓图输出 ├── record/ # 录像归档输出 │ └── 2024-06-17/ # 按日期归档 └── alert/ # 告警事件切片

这套结构的好处是:所有输出路径都相对于根目录,脚本里用BASE_DIR变量统一引用,移动整个目录到新服务器时只需要改一个变量。安全方面也方便,可以给record/单独挂载 NAS,不用动脚本逻辑。

环境就绪后,先手动跑一条测试命令,验证摄像头 RTSP 流是否可达:

ffmpeg -rtsp_transport tcp -i "rtsp://user:pass@192.168.10.20:554/Streaming/Channels/101" -t 10 -c copy -f mpegts /opt/ffmpeg_scripts/tmp/test.ts

这条命令的意思是:用 TCP 方式拉流,采集 10 秒,不重新编码(-c copy),封装成 TS 格式输出到临时目录。如果这条能顺利跑完,说明网络、认证、解码都没问题。注意这里我用的是-rtsp_transport tcp,很多人默认 UDP,但园区网络比较复杂,跨交换机、防火墙后 UDP 丢包会导致花屏,TCP 在弱网环境下更稳。

3. 核心脚本实现:循环采集、定时抓图与文件清理

环境没问题之后,就可以开始写核心脚本了。这部分是整个自动化方案的主干,我会把三个最实用的脚本拆开讲:循环录像采集、定时抓图、周期清理。这三个并非孤立的,而是共同构成一条完整的“视频数据管线”。

3.1 循环录像采集脚本:用 while 而不是 for

先说录像采集。园区的需求通常是“重点区域持续录制、按时段轮转覆盖”,也就是常说的循环录像。FFmpeg 本身不提供循环录制功能,它只能一次拉流写一个文件,写满就退出。所以我们要在脚本里做循环调度:每录完一段,重新拉流再录下一段。

我写过一个比较成熟的采集脚本,核心逻辑如下:

#!/bin/bash # 循环录像采集脚本 STREAM_URL="rtsp://user:pass@192.168.10.20:554/Streaming/Channels/101" RECORD_DIR="/opt/ffmpeg_scripts/record/$(date +%Y-%m-%d)" DURATION=600 mkdir -p "$RECORD_DIR" while true do # 生成文件名:摄像头编号_开始时间戳.mp4 TIMESTAMP=$(date +%Y%m%d_%H%M%S) OUTPUT="$RECORD_DIR/CAM101_$TIMESTAMP.mp4" ffmpeg -rtsp_transport tcp -i "$STREAM_URL" \ -t "$DURATION" \ -c copy \ -f mp4 \ -movflags +faststart \ "$OUTPUT" # 判断退出码,非 0 表示拉流异常,等待后重试 if [ $? -ne 0 ]; then echo "$(date) 拉流失败,5秒后重试" >> /opt/ffmpeg_scripts/logs/record_cam101.log sleep 5 continue fi # 正常录满一段,间隔 2 秒再录下一段,避免频繁拉流 sleep 2 done

为什么用while true而不是for循环?因为摄像头连接随时可能中断,while true天然支持断线重连。配合-t $DURATION参数,每段视频正好 10 分钟,即使中途断流重连,生成的文件也是完整的。

这里有一个重要的封装参数:-movflags +faststart。如果不加这个参数,MP4 文件的 moov 元数据会被写在文件尾部,导致文件没“写完”之前无法播放。加了+faststart后,FFmpeg 会把元数据挪到文件头部,哪怕录制过程中断电,文件也能被播放器识别,对园区安防场景尤其关键。

另外注意,-c copy是纯流复制,不做转码,CPU 占用极低。之所以能这么做,是因为大部分摄像头输出的就是 H.264 编码,容器从 RTSP 封装的 TS 流换成 MP4,不需要重新压缩。如果摄像头输出的是 H.265,有些旧播放器不兼容,那就必须转码,这部分放到后面“参数调优指南”里细说。

3.2 定时抓图:用 curl 和 FFmpeg 双通道保障

录像之外,定时抓图也是园区的刚需。比如周界摄像头每 5 分钟抓一张图,存到一张“巡检总览”目录,方便安保在电脑上快速浏览,不用逐个打开视频。

我用的抓图脚本比较简洁:

#!/bin/bash # 定时抓图脚本 STREAM_URL="rtsp://user:pass@192.168.10.20:554/Streaming/Channels/102" SNAPSHOT_DIR="/opt/ffmpeg_scripts/capture/CAM102" mkdir -p "$SNAPSHOT_DIR" TIMESTAMP=$(date +%Y%m%d_%H%M%S) ffmpeg -rtsp_transport tcp -i "$STREAM_URL" \ -frames:v 1 \ -q:v 3 \ -y "$SNAPSHOT_DIR/CAM102_$TIMESTAMP.jpg"

核心参数是-frames:v 1,表示只抓一帧就退出。-q:v 3是 JPEG 质量,数值越小质量越高,3 已经能满足事后取证需求。-y是覆盖同名文件,避免因时间戳重复导致停止。

但这里有个现实问题:部分园区摄像头的 RTSP 流有“开门延迟”,拉流后需要 2-3 秒才能出首帧。如果脚本配的是 cron 每分钟触发,偶发情况下可能连 FFmpeg 还没拿到帧,cron 就结束了,留下一个空文件。我的对策是双通道抓图:先用摄像头自带的 HTTP 快照接口(如果有)抓一张,再用 FFmpeg 抓一张,取两个文件里较大的那个。摄像头自带的快照接口一般长这样:

curl -u user:pass "http://192.168.10.20:80/cgi-bin/snapshot.cgi" -o "$SNAPSHOT_DIR/CAM102_HTTP_$TIMESTAMP.jpg"

HTTP 快照秒出,但可能分辨率和画质不如 FFmpeg 抓的。所以最终保留规则是:如果 FFmpeg 抓的文件大小大于 HTTP 的,删掉 HTTP 的;否则反过来。这样能最大程度保证可用性和画质的平衡。

这个双通道逻辑后来帮了大忙。有一段时间某摄像头的 RTSP 流因固件 bug 不定期卡死,但 HTTP 快照完全正常,导致园区监控中心只看到了 HTTP 那张图,及时发现异常后让厂商重启设备,才避免了“有录像没画质”的尴尬。

3.3 文件清理:防止磁盘被录满

循环录像最怕什么?硬盘被塞满。录满了,FFmpeg 写文件失败,脚本就断了。所以清理逻辑必须和采集逻辑双轨并行。

我的清理脚本思路是按“保留天数 + 最小可用空间”双重条件判断:

#!/bin/bash # 清理录像文件 RECORD_BASE="/opt/ffmpeg_scripts/record" RETENTION_DAYS=30 MIN_FREE_GB=20 # 删除超过保留天数的目录 find "$RECORD_BASE" -maxdepth 1 -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \; # 检查磁盘空间,低于阈值则额外清理最旧的一天 FREE_KB=$(df -P /opt/ffmpeg_scripts | awk 'NR==2 {print $4}') FREE_GB=$((FREE_KB / 1024 / 1024)) if [ $FREE_GB -lt $MIN_FREE_GB ]; then OLDEST_DIR=$(ls -dt "$RECORD_BASE"/*/ | tail -1) if [ -n "$OLDEST_DIR" ]; then rm -rf "$OLDEST_DIR" echo "$(date) 空间不足,额外清理 $OLDEST_DIR" >> /opt/ffmpeg_scripts/logs/cleanup.log fi fi

这里有两个细节值得说。第一,-mtime +30是基于文件系统 mtime(修改时间)判断,当天刚写的文件不会被删。第二,ls -dt ... | tail -1是最简单有效的“找最旧目录”方式,虽然不算优雅,但在服务器上可靠,不需要额外装工具。还有一种更严谨的写法是用find找最旧的子目录,但对几十个目录量级的园区场景,ls -dt完全够用。

清理脚本的执行频率建议和录像脚本保持一致,比如每天凌晨 3 点跑一次。这样既不会影响白天的正常写入,也能在低峰期把空间腾出来。如果园区录像量特别大,可以把频率提到每小时一次。

4. 定时调度与日志告警:让脚本自动转起来

脚本写得再好,不能自动跑就是废纸。定时调度在 Linux 下首选 cron。我在这里分享一套我自己觉得比较舒服的调度写法,以及配套的日志和告警机制。

4.1 cron 配置的最佳实践

crontab 的配置看起来简单,但坑不少。先看我常用的配置:

# 录像采集:每 10 分钟自动拉起采集脚本(如果发现相同脚本已在跑则跳过) */10 * * * * /bin/bash /opt/ffmpeg_scripts/bin/cycle_record_cam101.sh >> /opt/ffmpeg_scripts/logs/cron_cam101.log 2>&1 # 定时抓图:每 5 分钟一次 */5 * * * * /bin/bash /opt/ffmpeg_scripts/bin/snapshot_all.sh >> /opt/ffmpeg_scripts/logs/cron_snapshot.log 2>&1 # 清理任务:每天凌晨 3 点 0 3 * * * /bin/bash /opt/ffmpeg_scripts/bin/cleanup_record.sh >> /opt/ffmpeg_scripts/logs/cron_cleanup.log 2>&1

第一行是录像采集的 cron。你可能要问:之前不是说采集脚本用while true循环吗?为什么还要*/10触发?这里要解释一下:while true循环是“守护进程”式的,一旦脚本本身异常退出(比如被 kill),cron 会在下一个 10 分钟周期把它拉起来。所以 cron 和while true是双重保险。为了防止重复启动,需要在采集脚本开头加一个“单实例检查”:

LOCK_FILE="/tmp/record_cam101.lock" exec 9>"$LOCK_FILE" if ! flock -n 9; then echo "已有采集脚本在运行,退出" exit 1 fi

flock -n 9这个用法非常经典:打开一个文件作为锁文件,用文件描述符 9 持有它,再尝试加锁。如果加锁失败,说明已经有实例在跑,直接退出。这个方案比pidof判断锁健壮得多,因为进程残留 PID 文件的情况在异常退出后很常见,而flock是内核级别锁,进程死后自动释放。

4.2 日志:脚本的“仪表盘”

日志是排查问题的第一现场。我所有的脚本都强制要求输出三样内容:时间、动作、结果。比如:

2024-06-17 03:00:01 开始清理录像 2024-06-17 03:00:05 已清理 /opt/ffmpeg_scripts/record/2024-05-17 2024-06-17 03:00:05 当前剩余空间 45.3GB

不要嫌日志多占空间,每条日志十几字节,一百条才 1KB,硬盘根本不在乎。关键是格式要统一。我建议所有脚本的日志都追加到logs/目录下,并且按脚本名命名,这样哪个脚本出错,一眼就能定位。

日志轮转也别忘了。长时间运行后日志会越来越大,用logrotate或者简单的head -n截断都行。我最简的处理是每周执行一次:

tail -n 5000 /opt/ffmpeg_scripts/logs/record_cam101.log > /tmp/record_log_temp.log mv /tmp/record_log_temp.log /opt/ffmpeg_scripts/logs/record_cam101.log

这样保证日志文件不会无限膨胀,又能保留最近的执行记录。园区项目往往一年半载没人去看日志,不清的话一个文件可能积累到几 GB,影响排查。

4.3 异常告警:别等问题被放大才发现

脚本链路里最容易被忽视的是“没人看日志”。如果当天录像失败了,第二天才发现,园区的事件回溯就晚了。所以告警机制必须有。

告警方式有很多,最简单的就是邮件告警。Linux 自带mailx或sendmail,脚本里判断失败后调用发送。我的告警逻辑长这样:

if [ $? -ne 0 ]; then echo "$(date) 拉流失败:$STREAM_URL" >> "/opt/ffmpeg_scripts/logs/record_cam101.log" # 连续失败超过 3 次才发告警,避免抖动导致频繁骚扰 FAIL_COUNT_FILE="/tmp/record_cam101_fail_count" FAIL_COUNT=$(cat "$FAIL_COUNT_FILE" 2>/dev/null || echo 0) FAIL_COUNT=$((FAIL_COUNT + 1)) echo "$FAIL_COUNT" > "$FAIL_COUNT_FILE" if [ $FAIL_COUNT -ge 3 ]; then echo "录像采集失败已达 $FAIL_COUNT 次,请检查" | mailx -s "【告警】CAM101 录像异常" admin@example.com echo 0 > "$FAIL_COUNT_FILE" fi fi

这个“连续失败计数”的思路很实用。摄像头的 RTSP 流偶尔会因为网络抖动断一下,如果每次抖动都发告警,告警邮件很快就会被淹没。只有连续失败 3 次以上,才真的值得人工介入。计数的临时文件放在/tmp下即可,重启服务器后自动清空,正好避免一次历史故障在系统重启后被误报。

5. 场景参数调优:码率控制、GPU 加速与录像格式选择

脚本框架搭建完,剩下的都是磨刀工夫。园区项目的摄像头品牌杂,编码格式不一,同一个脚本不能一套参数吃遍所有摄像头。这一节我把实践中验证过的几个调优参数和场景对应关系整理一下。

5.1 码率控制:别让转码拖垮服务器

如果摄像头输出 H.264,-c copy直接封装,码率和源流一致,这个没得调。但如果遇到 H.265 的老摄像头,播放器不兼容,就必须转成 H.264。这时码率控制就是核心问题。

看这个转码参数组合:

ffmpeg -rtsp_transport tcp -i "$STREAM_URL" -t 60 \ -c:v libx264 -preset veryfast -crf 23 \ -c:a aac -b:a 64k \ -f mp4 "$OUTPUT"

-preset veryfast和-crf 23是黄金组合。-preset 影响编码速度和压缩率,veryfast在保证质量的前提下尽量跑快,适合实时场景。-crf 是质量常数,23 是均衡值;数值越小画质越好但文件越大。如果园区只要求“人眼能看清”,23 足够了,文件大小和源流接近。如果 CCTV 需要晚上看车牌,建议把 crf 降到 18,但 CPU 占用会翻倍。

更细致一点,可以设置-maxrate和-bufsize限制峰值码率,防止某个剧烈运动的画面把带宽打满:

-c:v libx264 -preset veryfast -crf 23 -maxrate 4M -bufsize 8M

服务器只有 4 核,同时转 3 路 H.265 就有点吃力。所以我在项目里做了个简单的策略:白天光线好的摄像头只做-c copy,夜间需要增强画质的才转码。这本质上是一个“按需转码”的调度逻辑,脚本里判断一下当前时间即可。

5.2 硬件加速:用 GPU 给 CPU 减负

如果园区有几路摄像头确实需要全天转码,纯 CPU 转码会占掉大部分算力。这时候可以考虑 NVIDIA 的 NVENC 或 Intel 的 QSV 硬件编码。

NVENC 的 FFmpeg 调用很简单:

ffmpeg -rtsp_transport tcp -i "$STREAM_URL" -t 60 \ -c:v h264_nvenc -preset p4 -cq 23 \ -c:a aac -b:a 64k \ -f mp4 "$OUTPUT"

注意驱动和 FFmpeg 版本的兼容性。NVENC 在不同显卡架构上支持的编码能力不同,老卡不支持 B 帧,参数设置有差异。实际项目里,我在一台带 T4 卡的服务器上试过,转码 4 路 1080p 的 CPU 占用不到 20%,比纯 CPU 省了一半多。如果你不差卡,硬件加速是首选。

但如果服务器没有独显,Intel 的核显 QSV 也能用:

-c:v h264_qsv -global_quality 23

QSV 依赖 Intel Media SDK,需确认内核版本和驱动。部分云服务器默认没有加载核显驱动,跑起来会报Device creation failed。这种情况就得退回 CPU 方案。

5.3 录像格式与时间戳水印

录像格式我一般用 MP4,但园区监控场景有一种更稳妥的选择:TS 格式。TS 封装对断流容忍度高,就算文件没写完,最后几秒损坏也可以播放。MP4 则不然,moov 元数据缺失时整个文件废掉。我现在的做法是:常规录像用 MP4(配+faststart),如果摄像头信号弱、断流频繁,那一路就换成 TS。

还有一个小但很实用的调优:水印打时间戳。FFmpeg 用drawtext滤镜可以实现:

ffmpeg -rtsp_transport tcp -i "$STREAM_URL" -t 60 -c:v libx264 -preset veryfast -crf 23 \ -vf "drawtext=text='CAM101 %{localtime\\:%Y-%m-%d %H\\:%M\\:%S}':fontsize=24:fontcolor=yellow:box=1:boxcolor=black@0.5:boxborderw=5:x=10:y=10" \ -f mp4 -movflags +faststart "$OUTPUT"

时间戳水印在事后取证时特别重要。没有水印,视频里很难证明“这段是哪天的录像”,就算有文件名的日期也可能被修改。加上水印后,物业和警方可以直接依据视频内容做判断。注意drawtext的转义很麻烦,冒号和百分号都要双重转义,初学时经常在这里报错,建议先用-vf "drawtext=text='hello':fontsize=24"测试通了再上复杂文本。

6. 常见问题与排查清单:照着这张表查就完了

脚本跑久了,一定会遇到各种奇奇怪怪的问题。我把这几年在园区项目里踩过的坑整理成了一张速查表,照着一项项排查,至少能解决九成的故障。

现象可能原因排查命令/方法解决方案
FFmpeg 拉流报 401 UnauthorizedRTSP 认证失败确认 rtsp URL 中的 user:pass 是否正确修改 URL,有些摄像头需 URL 编码特殊字符
拉流卡死,无任何日志输出摄像头 RTSP 流异常,FFmpeg 默认不会超时退出手动跑timeout 30 ffmpeg -i ...看是否卡住加-stimeout 5000000(微秒),5 秒握手超时
生成的 MP4 文件无法播放缺少 moov 元数据,文件未“写完整”ffprobe file.mp4报错加-movflags +faststart,或改用 TS 封装
抓图正常但录像为空文件摄像头设置了“仅子码流可快照”检查摄像头编码配置改用子码流拉流录长录像,或调换码流索引
flock报锁文件被占用上次脚本异常退出,锁文件残留ls -l /tmp/xxx.lock不用手动删,重启或下次脚本成功后会释放
清理脚本删了不该删的目录find 的-mtime计算误差、或路径写错find /opt/ffmpeg_scripts/record -maxdepth 1 -mtime +7先预览先跑 dry-run 模式,确认后再执行删除
cron 环境中 FFmpeg 命令找不到PATH 不完整,cron 默认环境变量很少在脚本开头export PATH=$PATH:/usr/local/bin统一用绝对路径跑 FFmpeg
多路摄像头拉同一路流导致带宽打满每个进程独立拉流,重复占用带宽nethogs查看带宽占用用 RTSP relay(如 MediaMTX)或只拉一路再本地复制

这张表里最值得展开的是“FFmpeg 卡死后无日志”的问题。很多脚本第一次上线时都会“装死”,因为 FFmpeg 在遇到 TCP 连接超时时,默认会一直等下去,除非收到信号。所以我在所有拉流命令里都会加-stimeout 5000000 -rw_timeout 5000000,分别是 socket 握手超时和读写超时,单位是微秒,5000000 就是 5 秒。加了它,FFmpeg 遇到死链能在 5 秒内退出,脚本就能走下一步逻辑,而不是卡一整天。

另一个高频坑是 cron 环境里的 PATH。cron 的 PATH 默认很简单,/usr/bin:/bin,而手动登录环境通常有/usr/local/bin。如果 FFmpeg 装在/usr/local/bin,手动跑没问题,cron 跑就报command not found。这个坑我踩过一次,后来习惯在脚本开头统一export PATH=$PATH:/usr/local/bin,再顺手把脚本里的命令全改成绝对路径,彻底断了这个念头。

7. 实操心得与后续扩展方向

整套自动化脚本在园区上线跑了快半年,整体稳定,期间只出过两次小故障,一次是某摄像头电源松动导致连续 6 个小时断流,另一次是 NAS 空间被其他项目数据占满导致录像文件写到一半失败。这两次都触发了我们的告警机制,处理得很及时,没有造成过长时间的视频缺失。

我个人最大的体会是:脚本不在于写得多么华丽,而在于“异常时能不能按预期收场”。FFmpeg 是工具,Shell 是调度,但真正决定系统可靠性的是各种边界条件的处理——超时重连、单实例锁、连续失败告警、磁盘空间熔断。如果这些细节都做好了,这套系统基本就能“长跑”了。

后续如果项目要加新摄像头,只改脚本里的STREAM_URL和目录就行,不用动核心框架。再往后,如果引入了 AI 分析、人脸识别这些上层应用,Shell 脚本这段是现成的数据管道,把抓图的路径交给算法平台即可。这也是我当时坚持把采集层做成“无状态脚本”的原因——上层的任何扩展,都不用回头改底层的数据采集方式。

最后分享一个小技巧:所有脚本在正式跑 cron 之前,先手动执行个 2-3 遍,把日志里的时间戳和输出路径核对一遍。不要直接丢进 cron 就以为万事大吉。我在项目里吃过一次亏:把*/5写成了5 * * * *,导致抓图任务每小时只在第五分钟跑一次,半天没发现。事后只要养成了“先手动、再 cron、后观察三天”的习惯,这类低级错误基本能避免。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询