前言
在日常开发工作中,我们经常需要重复执行一些特定的操作,比如批量处理文件、自动化部署、数据处理等。如果能够构建一个属于自己的命令行工具,通过简短的指令快速执行这些任务,将大大提升工作效率。
本文将手把手教你如何从零开始构建一个可扩展的自定义命令行工具,实现自己的指令体系。
技术选型
- 语言: Python 3.x (简单易用,跨平台)
- 核心特性 :
- 命令解析与分发
- 插件化指令扩展
- 参数处理
- 友好的帮助信息
完整源码实现
主程序 mycli.py
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自定义命令行工具 - MyCLI
作者: Your Name
日期: 2025-10-21
"""
import sys
import os
from typing import Dict, Callable, List
import json
from datetime import datetime
class CommandRegistry:
"""命令注册器 - 管理所有自定义指令"""
def __init__(self):
self.commands: Dict[str, Callable] = {}
self.descriptions: Dict[str, str] = {}
def register(self, name: str, description: str):
"""装饰器: 注册命令"""
def decorator(func: Callable):
self.commands[name] = func
self.descriptions[name] = description
return func
return decorator
def execute(self, command: str, args: List[str]):
"""执行命令"""
if command in self.commands:
try:
return self.commands[command](args)
except Exception as e:
print(f"❌ 执行错误: {e}")
return False
else:
print(f"❌ 未知命令: {command}")
print("💡 使用 'help' 查看所有可用命令")
return False
def show_help(self):
"""显示帮助信息"""
print("\n" + "="*50)
print("🚀 MyCLI - 自定义命令行工具")
print("="*50)
print("\n📋 可用命令:\n")
for name, desc in self.descriptions.items():
print(f" {name:<15} - {desc}")
print("\n" + "="*50)
print("💡 使用方法: mycli <命令> [参数...]")
print("="*50 + "\n")
# 创建全局命令注册器
registry = CommandRegistry()
# ==================== 定义自定义命令 ====================
@registry.register("hello", "打招呼命令")
def cmd_hello(args: List[str]):
"""打招呼"""
name = args[0] if args else "World"
print(f"👋 Hello, {name}!")
return True
@registry.register("time", "显示当前时间")
def cmd_time(args: List[str]):
"""显示当前时间"""
now = datetime.now()
print(f"⏰ 当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}")
return True
@registry.register("calc", "简单计算器 (支持: +, -, *, /)")
def cmd_calc(args: List[str]):
"""计算器"""
if len(args) < 3:
print("❌ 用法: calc <数字1> <操作符> <数字2>")
print(" 示例: calc 10 + 5")
return False
try:
num1 = float(args[0])
operator = args[1]
num2 = float(args[2])
operations = {
'+': lambda x, y: x + y,
'-': lambda x, y: x - y,
'*': lambda x, y: x * y,
'/': lambda x, y: x / y if y != 0 else None
}
if operator not in operations:
print(f"❌ 不支持的操作符: {operator}")
return False
result = operations[operator](num1, num2)
if result is None:
print("❌ 错误: 除数不能为0")
return False
print(f"🧮 计算结果: {num1} {operator} {num2} = {result}")
return True
except ValueError:
print("❌ 错误: 请输入有效的数字")
return False
@registry.register("file", "文件操作 (list|create|delete)")
def cmd_file(args: List[str]):
"""文件操作"""
if not args:
print("❌ 用法: file <操作> [参数]")
print(" 操作: list, create <文件名>, delete <文件名>")
return False
operation = args[0]
if operation == "list":
print("📁 当前目录文件列表:")
files = os.listdir('.')
for i, file in enumerate(files, 1):
icon = "📂" if os.path.isdir(file) else "📄"
print(f" {i}. {icon} {file}")
return True
elif operation == "create" and len(args) > 1:
filename = args[1]
try:
with open(filename, 'w', encoding='utf-8') as f:
f.write(f"# 创建于 {datetime.now()}\n")
print(f"✅ 文件已创建: {filename}")
return True
except Exception as e:
print(f"❌ 创建失败: {e}")
return False
elif operation == "delete" and len(args) > 1:
filename = args[1]
try:
if os.path.exists(filename):
os.remove(filename)
print(f"✅ 文件已删除: {filename}")
return True
else:
print(f"❌ 文件不存在: {filename}")
return False
except Exception as e:
print(f"❌ 删除失败: {e}")
return False
else:
print("❌ 无效的操作")
return False
@registry.register("note", "笔记管理 (add|list|clear)")
def cmd_note(args: List[str]):
"""简单笔记管理"""
note_file = ".mycli_notes.json"
# 加载笔记
def load_notes():
if os.path.exists(note_file):
with open(note_file, 'r', encoding='utf-8') as f:
return json.load(f)
return []
# 保存笔记
def save_notes(notes):
with open(note_file, 'w', encoding='utf-8') as f:
json.dump(notes, f, ensure_ascii=False, indent=2)
if not args:
print("❌ 用法: note <操作> [内容]")
print(" 操作: add <内容>, list, clear")
return False
operation = args[0]
if operation == "add" and len(args) > 1:
notes = load_notes()
content = ' '.join(args[1:])
note_entry = {
"id": len(notes) + 1,
"content": content,
"time": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
notes.append(note_entry)
save_notes(notes)
print(f"✅ 笔记已添加 (ID: {note_entry['id']})")
return True
elif operation == "list":
notes = load_notes()
if not notes:
print("📝 暂无笔记")
else:
print(f"📝 共有 {len(notes)} 条笔记:\n")
for note in notes:
print(f" [{note['id']}] {note['time']}")
print(f" {note['content']}\n")
return True
elif operation == "clear":
if os.path.exists(note_file):
os.remove(note_file)
print("✅ 所有笔记已清空")
return True
else:
print("❌ 无效的操作")
return False
@registry.register("env", "显示环境变量")
def cmd_env(args: List[str]):
"""显示环境变量"""
if args:
# 显示特定环境变量
var_name = args[0]
value = os.environ.get(var_name)
if value:
print(f"🔧 {var_name} = {value}")
else:
print(f"❌ 环境变量不存在: {var_name}")
else:
# 显示所有环境变量
print("🔧 环境变量列表:\n")
for key, value in sorted(os.environ.items()):
print(f" {key} = {value}")
return True
@registry.register("help", "显示帮助信息")
def cmd_help(args: List[str]):
"""显示帮助"""
registry.show_help()
return True
@registry.register("exit", "退出程序")
def cmd_exit(args: List[str]):
"""退出"""
print("👋 再见!")
sys.exit(0)
# ==================== 主程序 ====================
def main():
"""主函数"""
print("\n🚀 欢迎使用 MyCLI!")
print("💡 输入 'help' 查看所有命令,输入 'exit' 退出\n")
# 交互模式
if len(sys.argv) == 1:
while True:
try:
user_input = input("MyCLI> ").strip()
if not user_input:
continue
parts = user_input.split()
command = parts[0]
args = parts[1:] if len(parts) > 1 else []
registry.execute(command, args)
except KeyboardInterrupt:
print("\n\n👋 再见!")
break
except EOFError:
print("\n\n👋 再见!")
break
# 命令行模式
else:
command = sys.argv[1]
args = sys.argv[2:] if len(sys.argv) > 2 else []
registry.execute(command, args)
if __name__ == "__main__":
main()
实现步骤详解
步骤 1: 设计命令注册器
命令注册器是整个系统的核心,负责:
- 注册命令与对应的处理函数
- 存储命令描述信息
- 分发和执行命令
python
class CommandRegistry:
def __init__(self):
self.commands = {} # 命令字典
self.descriptions = {} # 描述字典
步骤 2: 使用装饰器注册命令
通过装饰器模式,让命令注册变得优雅简洁:
python
@registry.register("hello", "打招呼命令")
def cmd_hello(args):
print(f"Hello, {args[0] if args else 'World'}!")
步骤 3: 实现命令执行逻辑
命令执行器负责:
- 查找命令
- 调用对应处理函数
- 处理异常情况
步骤 4: 添加交互模式
支持两种运行模式:
- 交互模式: 直接运行程序,进入命令提示符
- 命令行模式 :
python mycli.py <命令> [参数]
使用示例
1. 启动交互模式
bash
python mycli.py
输出:
🚀 欢迎使用 MyCLI!
💡 输入 'help' 查看所有命令,输入 'exit' 退出
MyCLI>
2. 查看帮助
bash
MyCLI> help
3. 使用计算器
bash
MyCLI> calc 100 + 50
🧮 计算结果: 100.0 + 50.0 = 150.0
4. 文件操作
bash
MyCLI> file list
📁 当前目录文件列表:
1. 📄 mycli.py
2. 📂 docs
MyCLI> file create test.txt
✅ 文件已创建: test.txt
5. 笔记管理
bash
MyCLI> note add 明天要完成项目文档
✅ 笔记已添加 (ID: 1)
MyCLI> note list
📝 共有 1 条笔记:
[1] 2025-10-21 15:30:00
明天要完成项目文档
6. 命令行模式
bash
python mycli.py hello Python
👋 Hello, Python!
python mycli.py time
⏰ 当前时间: 2025-10-21 15:30:00
扩展建议
1. 添加配置文件支持
python
import configparser
def load_config():
config = configparser.ConfigParser()
config.read('mycli.conf')
return config
2. 添加日志功能
python
import logging
logging.basicConfig(
filename='mycli.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
3. 实现插件系统
python
# plugins/my_plugin.py
@registry.register("mycommand", "我的自定义命令")
def my_command(args):
print("这是我的插件命令!")
4. 添加命令别名
python
class CommandRegistry:
def __init__(self):
self.aliases = {
'h': 'help',
'q': 'exit',
'ls': 'file list'
}
5. 参数验证
python
from typing import List, Optional
def validate_args(args: List[str],
min_args: int = 0,
max_args: Optional[int] = None) -> bool:
if len(args) < min_args:
return False
if max_args and len(args) > max_args:
return False
return True
项目优化
性能优化
- 懒加载: 只在使用时加载命令模块
- 缓存: 缓存频繁访问的数据
- 异步处理: 对于耗时操作使用异步
用户体验优化
- 命令补全: 集成 readline 库实现 Tab 补全
- 彩色输出: 使用 colorama 库美化输出
- 进度条: 使用 tqdm 显示长任务进度
python
# 命令补全示例
import readline
def completer(text, state):
options = [cmd for cmd in registry.commands.keys()
if cmd.startswith(text)]
return options[state] if state < len(options) else None
readline.set_completer(completer)
readline.parse_and_bind('tab: complete')
部署与分发
1. 创建可执行脚本
bash
chmod +x mycli.py
2. 添加到系统 PATH
bash
# Linux/Mac
export PATH=$PATH:/path/to/mycli
# Windows
setx PATH "%PATH%;C:\path\to\mycli"
3. 创建 setup.py 打包
python
from setuptools import setup
setup(
name='mycli',
version='1.0.0',
py_modules=['mycli'],
entry_points={
'console_scripts': [
'mycli=mycli:main',
],
},
)
安装:
bash
pip install -e .
总结
通过本文,我们完整实现了一个可扩展的自定义命令行工具。主要特点:
✅ 模块化设计 : 命令注册器 + 装饰器模式
✅ 易于扩展 : 添加新命令只需一个装饰器
✅ 双模式支持 : 交互模式 + 命令行模式
✅ 友好交互 : 清晰的提示和错误处理
✅ 实用功能: 计算器、文件操作、笔记管理等
这个框架可以根据你的需求无限扩展,打造属于自己的效率工具集!