刚接触Mac开发的程序员经常会遇到这样的场景:每天凌晨需要自动备份数据库、每小时要检查服务器状态、每周五下午要给团队发周报...如果每次都手动操作,不仅效率低下还容易忘记。这时候就该crontab出场了。
crontab是Unix/Linux系统内置的定时任务管理工具,Mac系统作为Unix分支自然也支持。它就像个永不休息的机器人管家,可以精确到分钟级别执行你安排的任务。我团队里的运维小哥用它自动处理日志分析、数据同步等重复工作,省下大量时间摸鱼(划掉)研究新技术。
与Mac自带的"日历提醒"或"自动化工具"不同,crontab的优势在于:
打开终端输入:
bash复制crontab -l
如果显示"no crontab for user",说明还没创建过任务。别担心,这很正常。
输入编辑命令:
bash复制crontab -e
这时会进入vim编辑界面(新手注意:按i进入编辑模式)。我们来添加一个简单的任务:
bash复制* * * * * say "你的任务正在运行" >> ~/cron_test.log 2>&1
保存退出(ESC后输入:wq)。这个任务会让Mac每分钟用语音提示你,同时把记录写入日志文件。
等1分钟后,检查用户目录下的日志文件:
bash复制cat ~/cron_test.log
如果看到时间戳和语音提示,恭喜你!第一个定时任务已经跑起来了。
crontab的时间字段就像密码锁:
code复制* * * * * command
┬ ┬ ┬ ┬ ┬
│ │ │ │ │
│ │ │ │ └── 星期几 (0-6, 0是周日)
│ │ │ └──── 月份 (1-12)
│ │ └────── 日期 (1-31)
│ └──────── 小时 (0-23)
└────────── 分钟 (0-59)
特殊符号用法:
, 表示多个时间点:15,45 * * * *(每小时的15分和45分)- 表示区间:0 9-18 * * *(早9点到晚6点整点)*/n 表示间隔:*/5 * * * *(每5分钟)案例1:每日数据库备份
bash复制0 3 * * * /usr/local/bin/mysqldump -u root -p密码 数据库名 > ~/backups/db_$(date +\%Y\%m\%d).sql
(注意:%需要转义)
案例2:监控磁盘空间
bash复制0 */2 * * * df -h | grep -E '90%|100%' | mail -s "磁盘告警" admin@example.com
案例3:自动清理临时文件
bash复制0 0 * * 0 find /tmp -type f -mtime +7 -delete
这是新手最容易栽的坑。手动执行正常的脚本,放到crontab里就报错"command not found"。因为crontab的执行环境是精简的,不会加载你的bash_profile。
解决方案1:使用绝对路径
bash复制0 * * * * /usr/local/bin/python3 ~/scripts/alert.py
解决方案2:显式加载环境
bash复制0 * * * * source ~/.zshrc && /Users/me/scripts/sync_data.sh
crontab默认以当前用户身份运行,如果脚本需要读写特定目录,记得:
bash复制chmod +x your_script.sh
chmod 600 ~/private_file.txt
不处理日志的话,系统邮件会爆满。推荐两种方式:
重定向到文件
bash复制* * * * * /path/to/script.sh >> ~/cron.log 2>&1
丢弃输出(适合不重要任务)
bash复制* * * * * /path/to/script.sh > /dev/null 2>&1
对于需要精确到秒或依赖系统状态的任务,Mac原生的launchd更合适。创建plist文件:
xml复制<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.myjob</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/script</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>
加载服务:
bash复制launchctl load ~/Library/LaunchAgents/com.example.myjob.plist
当任务不执行时:
bash复制sudo launchctl list | grep cron
bash复制grep cron /var/log/system.log
bash复制env -i /bin/sh -c "your_command"
bash复制security add-generic-password -a ${USER} -s "mysql_backup" -w
bash复制timeout 300 your_long_running_script.sh
在给电商系统做价格监控时,我们遇到过crontab任务随机丢失的灵异事件。后来发现是Mac的休眠机制导致——合上笔记本盖子时,cron任务会被暂停。解决方案是:
caffeinate保持系统唤醒:bash复制* * * * * caffeinate -i /path/to/important_script.sh
另一个痛点是时区问题。我们的服务器在东京,开发机在上海,测试环境在AWS美国区。最终统一方案:
bash复制TZ=Asia/Shanghai
0 8 * * * /scripts/daily_report.sh
最后给个实用建议:复杂的定时任务最好先写成脚本文件,再让crontab调用。这样既方便调试,又利于版本控制。我习惯把脚本都放在~/scripts/目录,用Git管理变更历史。