1. 为什么选择命令行待办事项应用?
在图形界面大行其道的今天,命令行工具依然保持着独特的生命力。我最初接触命令行待办事项是在2016年处理服务器维护时,当时需要快速记录几十台服务器的维护状态。图形界面工具在SSH连接下显得笨拙,而一个简单的命令行工具让我在终端里就能完成所有记录。
命令行待办事项的核心优势在于:
- 极致的响应速度:无需等待GUI加载,一个命令就能完成操作
- 脚本化能力:可以与其他命令行工具组合使用,比如通过管道将任务列表导出到文件
- 低资源消耗:在老旧设备或远程服务器上也能流畅运行
- 可编程性:方便开发者扩展功能或集成到其他系统中
我见过最巧妙的使用案例是一位运维工程师将每日巡检任务与命令行待办工具结合,通过cron定时生成待办项,完成检查后自动标记为已完成并生成报告。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础架构设计
2.1 数据存储方案选择
经过多次迭代,我发现SQLite是最适合命令行待办事项的存储方案。它不需要单独的服务进程,单个文件就能管理所有数据。下面是我的数据库表设计:
sql复制CREATE TABLE tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
status INTEGER DEFAULT 0, -- 0:待办, 1:已完成
priority INTEGER DEFAULT 2, -- 0:高, 1:中, 2:低
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
due_date TIMESTAMP
);
这个设计支持:
- 基本的增删改查操作
- 任务状态管理
- 优先级设置
- 截止日期提醒
2.2 命令行交互设计
良好的命令行交互应该遵循Unix哲学——每个工具只做好一件事。我建议采用子命令模式:
code复制todo add "购买食材" -d "牛奶、鸡蛋、面包" -p 1
todo list --priority high
todo complete 3
todo delete 5
提示:使用Python的argparse或Click库可以快速构建这样的命令行界面。Click特别适合复杂命令结构,它支持自动生成帮助信息。
3. 核心功能实现
3.1 任务添加与展示
实现添加功能时,要注意处理包含空格的任务标题。这是我的Python实现片段:
python复制def add_task(title, description=None, priority=2):
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
cursor.execute(
"INSERT INTO tasks (title, description, priority) VALUES (?, ?, ?)",
(title, description, priority)
)
conn.commit()
conn.close()
print(f"已添加任务: {title}")
展示任务时,我推荐使用tabulate库美化输出:
python复制from tabulate import tabulate
def list_tasks(filter_status=None):
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
query = "SELECT id, title, priority FROM tasks"
if filter_status is not None:
query += f" WHERE status = {filter_status}"
cursor.execute(query)
tasks = cursor.fetchall()
print(tabulate(
tasks,
headers=["ID", "任务", "优先级"],
tablefmt="grid"
))
3.2 任务状态管理
状态转换是待办事项的核心功能。常见的状态包括:
- 待办
- 进行中
- 已完成
- 已取消
我建议使用数字表示状态,便于存储和比较:
python复制STATUS_TYPES = {
0: "待办",
1: "进行中",
2: "已完成",
3: "已取消"
}
def update_status(task_id, new_status):
if new_status not in STATUS_TYPES:
raise ValueError("无效的状态值")
# 检查任务是否存在
if not task_exists(task_id):
print(f"错误: 任务ID {task_id} 不存在")
return
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
cursor.execute(
"UPDATE tasks SET status = ? WHERE id = ?",
(new_status, task_id)
)
conn.commit()
conn.close()
print(f"任务 {task_id} 状态已更新为 {STATUS_TYPES[new_status]}")
4. 高级功能扩展
4.1 任务搜索与过滤
随着任务量增加,搜索功能变得必不可少。我实现了多条件组合搜索:
python复制def search_tasks(keyword=None, status=None, priority=None):
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
query = "SELECT * FROM tasks WHERE 1=1"
params = []
if keyword:
query += " AND (title LIKE ? OR description LIKE ?)"
params.extend([f"%{keyword}%", f"%{keyword}%"])
if status is not None:
query += " AND status = ?"
params.append(status)
if priority is not None:
query += " AND priority = ?"
params.append(priority)
cursor.execute(query, params)
tasks = cursor.fetchall()
# 格式化输出...
4.2 数据导入导出
为了与其他工具协作,我添加了JSON导入导出功能:
python复制import json
def export_to_json(filename):
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
cursor.execute("SELECT * FROM tasks")
tasks = cursor.fetchall()
with open(filename, 'w') as f:
json.dump(tasks, f, indent=2)
print(f"已导出 {len(tasks)} 个任务到 {filename}")
def import_from_json(filename):
with open(filename) as f:
tasks = json.load(f)
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
for task in tasks:
cursor.execute(
"INSERT INTO tasks VALUES (?, ?, ?, ?, ?, ?, ?)",
task
)
conn.commit()
conn.close()
print(f"已从 {filename} 导入 {len(tasks)} 个任务")
5. 实用技巧与优化
5.1 命令行自动补全
使用argcomplete库可以为你的工具添加bash自动补全功能:
python复制import argcomplete
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command')
# 添加子命令...
argcomplete.autocomplete(parser)
args = parser.parse_args()
# 处理命令...
if __name__ == '__main__':
main()
然后在bashrc中添加:
bash复制eval "$(register-python-argcomplete todo)"
5.2 定期提醒功能
结合cron或系统定时任务,可以实现任务提醒。这是我使用的提醒脚本:
python复制from datetime import datetime
def check_due_tasks():
conn = sqlite3.connect(DB_FILE)
cursor = conn.cursor()
cursor.execute("""
SELECT id, title, due_date FROM tasks
WHERE status < 2 AND due_date IS NOT NULL
""")
now = datetime.now()
for task in cursor.fetchall():
task_id, title, due_date = task
if datetime.strptime(due_date, "%Y-%m-%d %H:%M:%S") < now:
print(f"提醒: 任务 [{task_id}] {title} 已过期!")
可以设置每小时运行一次这个脚本。
6. 跨平台兼容性处理
6.1 Windows特殊处理
在Windows上,需要注意:
- 路径分隔符使用os.path.join处理
- 颜色显示需要引入colorama
- 换行符统一处理
python复制import platform
from colorama import init
if platform.system() == 'Windows':
init(convert=True)
DB_FILE = os.path.join(os.getenv('APPDATA'), 'todo', 'tasks.db')
else:
DB_FILE = os.path.expanduser('~/.todo/tasks.db')
6.2 打包发布
使用PyInstaller可以打包成独立可执行文件:
bash复制pyinstaller --onefile --name todo todo.py
对于更专业的发布,可以创建各平台的包:
- Windows: NSIS或Inno Setup安装包
- macOS: .pkg或.dmg
- Linux: .deb或.rpm
7. 测试与质量保证
7.1 单元测试策略
我为核心功能编写了单元测试:
python复制import unittest
import tempfile
import os
class TestTodo(unittest.TestCase):
def setUp(self):
self.db_fd, self.db_path = tempfile.mkstemp()
os.environ['TODO_DB'] = self.db_path
init_db()
def tearDown(self):
os.close(self.db_fd)
os.unlink(self.db_path)
def test_add_task(self):
add_task("测试任务")
tasks = list_tasks()
self.assertEqual(len(tasks), 1)
self.assertEqual(tasks[0][1], "测试任务")
# 更多测试用例...
7.2 性能优化
当任务量超过1000条时,需要注意:
- 为常用查询字段添加索引
- 分页显示结果
- 延迟加载任务详情
sql复制CREATE INDEX idx_status ON tasks(status);
CREATE INDEX idx_priority ON tasks(priority);
8. 实际应用案例
8.1 与版本控制配合
我将todo工具集成到Git工作流中:
bash复制# 开始新功能开发时
todo add "实现用户登录功能" -p 0
# 完成一个任务后
git commit -m "完成用户登录功能"
todo complete 1
8.2 服务器维护记录
在维护多台服务器时,我会为每台服务器创建独立的任务列表:
bash复制ssh server1 "todo add '检查磁盘空间'"
ssh server2 "todo add '更新安全补丁'"
然后统一查看所有服务器的任务状态:
bash复制for server in server{1..10}; do
echo "=== $server ==="
ssh $server "todo list"
done
这个命令行待办事项工具虽然简单,但经过不断迭代已经成为了我日常工作中不可或缺的助手。从最初的简单脚本到现在功能完善的工具,最大的体会是:好的命令行工具应该像瑞士军刀一样,专注于解决特定问题,同时能与其他工具无缝协作。
