概述scripts/crontab_tool.py是一个 Python 脚本用于管理系统 crontab 定时任务。支持添加、删除、列出任务可作为公共方法复用适用于各种定时场景基金日报、数据备份、提醒推送等。为什么使用系统 crontab 而非 OpenClaw cron对比项OpenClaw cron (agentTurn)系统 crontabToken 消耗✅ 每次运行消耗 AI token❌ 零消耗调度可靠性依赖 OpenClaw 调度器系统级更稳定适用场景需要 AI 理解/推理的任务纯脚本执行任务日志管理内置需自行配置对于纯脚本执行如运行 Python 脚本发送报告系统 crontab 是更经济、更稳定的选择。使用方法添加任务python3 scripts/crontab_tool.pyadd\--expr30 20 * * 1-5\--commandcd /path python3 xxx.py\--name任务名称\--log-dir /path/to/logs参数说明参数必填说明--expr✅cron 表达式如5 15 * * 1-5--command✅要执行的命令--name否任务名称用于后续查找和删除--log-dir否日志目录传入后自动追加 stdout/stderr 重定向--no-comment否不在任务上方添加注释标记行示例# 添加基金日报指数基金实时估值python3 scripts/crontab_tool.pyadd\--expr5 15 * * 1-5\--commandcd /root/OpenClawWorkspace python3 scripts/fund_report.py --type index\--name指数基金实时估值\--log-dir /root/OpenClawWorkspace/logs# 添加基金日报主动基金收盘净值python3 scripts/crontab_tool.pyadd\--expr30 20 * * 1-5\--commandcd /root/OpenClawWorkspace python3 scripts/fund_report.py --type active\--name主动基金收盘净值\--log-dir /root/OpenClawWorkspace/logs列出所有任务python3 scripts/crontab_tool.py list输出示例 共 2 条 crontab 任务 2. 5 15 * * 1-5 cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type index /root/OpenClawWorkspace/logs/指数基金实时估值.log 21 [#指数基金实时估值] 4. 30 20 * * 1-5 cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type active /root/OpenClawWorkspace/logs/主动基金收盘净值.log 21 [#主动基金收盘净值] 删除任务按名称删除推荐python3 scripts/crontab_tool.py remove--name指数基金实时估值按行号删除python3 scripts/crontab_tool.py remove--line3查看原始 crontabcrontab-l任务命名约定每个任务在 crontab 中以注释行 命令的形式存储# crontab_tool: 指数基金实时估值 5 15 * * 1-5 cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type index /root/OpenClawWorkspace/logs/指数基金实时估值.log 21注释行# crontab_tool: {name}用于唯一标识任务方便后续查找和删除。作为公共方法调用脚本中的核心函数可以被其他 Python 脚本 import 复用fromscripts.crontab_toolimportadd_task,remove_task,list_tasks# 添加任务resultadd_task(expr0 8 * * 1-5,commandcd /path python3 script.py,name每日早间提醒,log_dir/path/to/logs)# 列出任务taskslist_tasks()fortintasks:print(f{t[line]}:{t[content]})# 删除任务remove_task(name每日早间提醒)当前已配置的任务任务名称cron 表达式命令日志指数基金实时估值5 15 * * 1-5python3 scripts/fund_report.py --type indexlogs/指数基金实时估值.log主动基金收盘净值30 20 * * 1-5python3 scripts/fund_report.py --type activelogs/主动基金收盘净值.logcron 表达式参考┌───────────── 分钟 (0-59) │ ┌───────────── 小时 (0-23) │ │ ┌───────────── 日 (1-31) │ │ │ ┌───────────── 月 (1-12) │ │ │ │ ┌───────────── 星期 (0-6, 0周日) │ │ │ │ │ * * * * *常用表达式表达式含义5 15 * * 1-5周一至周五 15:0530 20 * * 1-5周一至周五 20:300 9 * * *每天 9:000 0 * * 0每周日 0:00*/30 * * * *每 30 分钟相关文件#!/usr/bin/env python3 crontab_tool.py — 系统 crontab 任务管理工具 通过 Python 管理 Linux 系统 crontab 任务可添加、删除、列出任务。 后期可复用为公共方法用于添加不同的定时任务如基金日报、天气提醒、数据备份等。 使用方法: # 添加任务 python3 crontab_tool.py add --expr 30 20 * * 1-5 --command cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type active --name 主动基金收盘净值 # 添加任务带日志路径 python3 crontab_tool.py add --expr 5 15 * * 1-5 --command cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type index --name 指数基金实时估值 --log-dir /root/OpenClawWorkspace/logs # 列出所有任务 python3 crontab_tool.py list # 删除任务按名称匹配 python3 crontab_tool.py remove --name 指数基金实时估值 # 删除任务按行号 python3 crontab_tool.py remove --line 3 importsubprocessimportsysimportargparseimportreimportos# # 公共方法# defget_crontab():获取当前用户的 crontab 内容返回行列表resultsubprocess.run([crontab,-l],capture_outputTrue,textTrue,timeout10)ifresult.returncode0:returnresult.stdout.rstrip(\n).split(\n)ifresult.stdout.strip()else[]# crontab -l 可能返回 1无 crontab 时ifno crontabinresult.stderr.lower():return[]raiseRuntimeError(f获取 crontab 失败:{result.stderr})defset_crontab(lines):将行列表写入当前用户的 crontabcontent\n.join(lines)\niflineselseprocsubprocess.run([crontab,-],inputcontent,capture_outputTrue,textTrue,timeout10)ifproc.returncode!0:raiseRuntimeError(f写入 crontab 失败:{proc.stderr})returnTruedefadd_task(expr,command,nameNone,log_dirNone,commentTrue): 添加一条 crontab 任务 参数: expr: cron 表达式如 30 20 * * 1-5 command: 要执行的命令字符串 name: 任务名称用于后续查找和删除可选不传则自动生成 log_dir: 日志目录可选传入后自动追加 stdout/stderr 重定向 comment: 是否在任务上方添加注释行默认 True 返回: dict: {success: True, line: 行号, name: 名称} linesget_crontab()# 自动生成名称取命令的前 30 个字符ifnotname:namecommand[:30].strip()# 构建任务行iflog_dir:os.makedirs(log_dir,exist_okTrue)safe_namere.sub(r[^a-zA-Z0-9_\-\u4e00-\u9fff],_,name)log_fileos.path.join(log_dir,f{safe_name}.log)task_linef{expr}{command}{log_file}21else:task_linef{expr}{command}# 检查是否已存在同名任务通过注释行识别name_patternf# crontab_tool:{name}fori,lineinenumerate(lines):ifline.strip()name_pattern:return{success:False,error:f任务 {name} 已存在第{i1}行请先删除或使用不同的名称}# 添加任务注释 命令new_lines[]ifcomment:new_lines.append(f# crontab_tool:{name})new_lines.append(task_line)lines.extend(new_lines)set_crontab(lines)return{success:True,line:len(lines)-len(new_lines)1,name:name,expr:expr,command:command,log_dir:log_dir}defremove_task(nameNone,lineNone): 删除 crontab 任务 参数: name: 按任务名称删除匹配注释行 # crontab_tool: {name} 及下一行命令 line: 按行号删除1-indexed删除该行 返回: dict: {success: True, removed: 行数} linesget_crontab()ifnotlines:return{success:False,error:当前没有 crontab 任务}removed0ifnameisnotNone:# 找到注释行并删除注释行 下一行命令new_lines[]skip_nextFalsefori,lineinenumerate(lines):ifskip_next:skip_nextFalseremoved1continueifline.strip()f# crontab_tool:{name}:skip_nextTrue# 跳过下一行命令行removed1continuenew_lines.append(line)ifremoved0:return{success:False,error:f未找到名为 {name} 的任务}set_crontab(new_lines)return{success:True,removed:removed}eliflineisnotNone:ifline1orlinelen(lines):return{success:False,error:f行号{line}超出范围1-{len(lines)}}removed_linelines.pop(line-1)set_crontab(lines)return{success:True,removed:1,content:removed_line}return{success:False,error:请指定 --name 或 --line}deflist_tasks(): 列出当前所有 crontab 任务解析注释标记 返回: list[dict]: 每个任务包含 line, content, name(若有标记) linesget_crontab()tasks[]current_nameNonefori,lineinenumerate(lines):line_numi1strippedline.strip()ifstripped.startswith(# crontab_tool:):current_namestripped.split(# crontab_tool:,1)[1].strip()elifstripped.startswith(#):current_nameNoneelifstrippedandnotstripped.startswith(#):tasks.append({line:line_num,content:stripped,name:current_name})current_nameNonereturntasks# # CLI 入口# defmain():parserargparse.ArgumentParser(description系统 crontab 任务管理工具,formatter_classargparse.RawDescriptionHelpFormatter,epilog 使用示例: # 添加基金日报任务 %(prog)s add --expr 5 15 * * 1-5 --command cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type index --name 指数基金实时估值 --log-dir /root/OpenClawWorkspace/logs %(prog)s add --expr 30 20 * * 1-5 --command cd /root/OpenClawWorkspace python3 scripts/fund_report.py --type active --name 主动基金收盘净值 --log-dir /root/OpenClawWorkspace/logs # 列出所有任务 %(prog)s list # 删除任务 %(prog)s remove --name 指数基金实时估值 %(prog)s remove --line 3 )subparsersparser.add_subparsers(destaction,requiredTrue)# addadd_parsersubparsers.add_parser(add,help添加 crontab 任务)add_parser.add_argument(--expr,requiredTrue,helpcron 表达式如 30 20 * * 1-5)add_parser.add_argument(--command,requiredTrue,help要执行的命令)add_parser.add_argument(--name,help任务名称用于后续查找和删除)add_parser.add_argument(--log-dir,help日志目录传入后自动追加 stdout/stderr 重定向)add_parser.add_argument(--no-comment,actionstore_true,help不在任务上方添加注释行)# removeremove_parsersubparsers.add_parser(remove,help删除 crontab 任务)remove_parser.add_argument(--name,help按任务名称删除)remove_parser.add_argument(--line,typeint,help按行号删除)# listsubparsers.add_parser(list,help列出所有 crontab 任务)argsparser.parse_args()ifargs.actionadd:resultadd_task(exprargs.expr,commandargs.command,nameargs.name,log_dirargs.log_dir,commentnotargs.no_comment)ifresult[success]:print(f✅ 任务添加成功)print(f 名称:{result[name]})print(f 表达式:{result[expr]})print(f 命令:{result[command]})ifresult.get(log_dir):print(f 日志:{result[log_dir]}/)print(f 行号: 第{result[line]}行)else:print(f❌ 添加失败:{result[error]})sys.exit(1)elifargs.actionremove:resultremove_task(nameargs.name,lineargs.line)ifresult[success]:print(f✅ 删除成功已移除{result[removed]}行)ifresult.get(content):print(f 内容:{result[content]})else:print(f❌ 删除失败:{result[error]})sys.exit(1)elifargs.actionlist:taskslist_tasks()ifnottasks:print( 当前没有 crontab 任务)returnprint(f 共{len(tasks)}条 crontab 任务)print(*60)fortintasks:tagf [#{t[name]}]ift[name]elseprint(f{t[line]:3}.{t[content]}{tag})print(*60)if__name____main__:main()