# 目录树生成脚本 - 架构设计文档 项目 ID: PROJ-20260509011 | 任务 ID: T023 | 功能清单: F013-F020 设计者: 脚本架构师 | 日期: 2026-05-16 | 状态: 待审批 --- ## 1. 项目结构 ``` 项目根目录/ ├── tree.sh # 主脚本(单文件,约 300-400 行) ├── .treeignore # 忽略配置文件(可选,用户创建) ├── tree_output.md # 默认输出文件(脚本生成) └── README.md # 使用文档(后续任务产出) ``` 设计原则:单文件脚本,零安装依赖,即拿即用。 --- ## 2. 模块说明 ### 2.1 parse_args - 负责功能: F013 路径输入解析 - 输入: 命令行参数 - 输出: 规范化路径变量 TARGET_PATH - 依赖: bash 内置 getopts ### 2.2 load_ignore_config - 负责功能: F014 加载忽略配置 - 输入: .treeignore 文件路径 - 输出: 忽略模式数组 IGNORE_PATTERNS[] - 依赖: bash 内置 read/while ### 2.3 should_ignore - 负责功能: F014 忽略判断 - 输入: 目录名 + IGNORE_PATTERNS[] - 输出: 布尔值(0=不忽略, 1=忽略) - 依赖: bash 内置 case/模式匹配 ### 2.4 traverse_directory - 负责功能: F015 递归遍历 - 输入: 路径 + 忽略列表 + 缩进级别 - 输出: 目录树结构(嵌套关联数组) - 依赖: bash 内置 for/find ### 2.5 render_tree - 负责功能: F016 目录树渲染 - 输入: 目录树结构 - 输出: 格式化字符串(├──/└──) - 依赖: bash 内置字符串操作 ### 2.6 collect_files - 负责功能: F017 文件收集 - 输入: 路径 + 忽略列表 - 输出: 文件路径列表(数组) - 依赖: bash 内置 find ### 2.7 render_file_list - 负责功能: F017 文件树渲染 - 输入: 文件路径列表 - 输出: 格式化字符串(带完整路径) - 依赖: bash 内置字符串操作 ### 2.8 output_terminal - 负责功能: F018 终端输出 - 输入: 格式化字符串 - 输出: 终端显示 - 依赖: bash 内置 echo/printf ### 2.9 save_markdown - 负责功能: F019 Markdown 保存 - 输入: 格式化字符串 + 输出路径 - 输出: tree_output.md 文件 - 依赖: bash 内置重定向 ### 2.10 compute_stats - 负责功能: F020 统计信息 - 输入: 遍历结果 - 输出: 目录数、文件数、总大小 - 依赖: du/find/wc --- ## 3. 技术选型 ### 3.1 语言与运行时 - Bash 4.0+ — 支持关联数组,现代 Linux 发行版标配(已确认) - find (POSIX) — 递归遍历目录,支持 -name/-prune 过滤(已确认) - du (POSIX) — 计算目录总大小(已确认) - stat / ls (POSIX) — 获取文件大小,跨平台兼容(已确认) - wc (POSIX) — 统计行数/条目数(已确认) ### 3.2 第三方库 本项目不引入任何第三方库。全部使用 POSIX/Bash 内置工具,确保: - 零安装依赖,开箱即用 - 兼容所有主流 Linux 发行版(Ubuntu/CentOS/Debian/Arch 等) - 兼容 macOS(Bash 5.x / zsh 兼容模式) --- ## 4. 功能详细设计 ### 4.1 F013 - 路径输入解析 用法: ``` ./tree.sh [路径] [选项] ``` 选项: - `-p, --path <路径>` — 指定目标目录(支持相对/绝对路径) - `-o, --output <文件>` — 指定输出文件路径(默认 tree_output.md) - `-d, --depth ` — 限制递归深度(默认无限制) - `-f, --files` — 同时生成文件树 - `-s, --no-stats` — 不显示统计信息 - `-h, --help` — 显示帮助信息 - `-v, --version` — 显示版本信息 路径规范化:相对路径自动转换为绝对路径,使用 `cd + pwd` 组合实现。 ### 4.2 F014 - 忽略配置 配置方案:支持两级忽略配置 - 内置默认忽略列表(低优先级)— 硬编码在脚本中 - .treeignore 文件(高优先级)— 每行一个模式(支持 glob) 内置默认忽略: - .git .svn .hg — 版本控制 - node_modules vendor bower_components — 包管理 - __pycache__ *.pyc .pytest_cache — Python - .DS_Store Thumbs.db — 系统文件 - .idea .vscode .settings — IDE - dist build out target — 构建产物 - .next .nuxt .output — 框架产物 .treeignore 文件格式: ``` # 注释行(以 # 开头) vendor/ *.log temp/ ``` ### 4.3 F015 - 递归遍历目录 数据结构:使用 bash 关联数组存储树结构 ```bash declare -A TREE_NODES # 键=节点ID, 值="name|type|parent_id" declare -A TREE_CHILDREN # 键=父节点ID, 值=子节点ID列表(空格分隔) ``` 遍历算法:对目录中每个条目,先检查是否应忽略,再判断是目录还是文件。目录则递归深入(受深度限制),文件则直接加入节点。 ### 4.4 F016 - 目录树渲染 输出格式规范: ``` . ├── src/ │ ├── main.sh │ ├── utils/ │ │ ├── helpers.sh │ │ └── logger.sh │ └── config.sh ├── tests/ │ └── test_main.sh ├── .treeignore └── README.md ``` 渲染规则: - 根节点显示为 `.` - 中间节点前缀:`├── ` - 最后一个节点前缀:`└── ` - 目录名后缀 `/` - 缩进单位:`│ `(竖线 + 3空格)或 4空格(用于最后一项之后) ### 4.5 F017 - 文件树 输出格式: ``` 文件列表(共 N 个文件): ./src/main.sh ./src/utils/helpers.sh ./src/utils/logger.sh ./src/config.sh ./tests/test_main.sh .treeignore README.md ``` ### 4.6 F018 - 终端输出 - 使用 `printf` 替代 `echo` 确保跨平台一致性 - 支持彩色输出(可选,检测终端是否支持) - 统计信息以分隔线包围,醒目展示 ### 4.7 F019 - Markdown 保存 输出文件:`tree_output.md`(默认) Markdown 格式包含: - 标题:目录树 - 目标路径 - 生成时间戳 - 目录结构(代码块包裹) - 文件列表(有序列表) - 统计信息 ### 4.8 F020 - 统计信息 统计项: - 目录数 — 遍历过程中计数(排除忽略目录) - 文件数 — 遍历过程中计数(排除忽略文件) - 总大小 — `du -sb` 获取字节数,转换为人类可读格式 输出格式: ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 统计信息 目录数:12 文件数:45 总大小:2.3 MB ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` --- ## 5. 错误处理策略 ### 5.1 错误分类与处理 - 路径不存在(错误码 1)— 输出错误信息到 stderr,exit 1 - 无读取权限(错误码 2)— 输出错误信息到 stderr,exit 2 - 路径不是目录(错误码 3)— 输出错误信息到 stderr,exit 3 - 输出目录不可写(错误码 4)— 输出错误信息到 stderr,exit 4 - 深度参数无效(错误码 5)— 输出错误信息到 stderr,exit 5 - 权限不足子目录(非致命)— 跳过并警告 - 符号链接循环(非致命)— 检测并跳过,警告输出 ### 5.2 安全机制 - `set -euo pipefail` — 遇到错误退出、未定义变量报错、管道错误传播 - 符号链接循环检测 — inode 去重 - `trap cleanup EXIT` — 脚本退出时清理临时资源 ### 5.3 警告 vs 错误 - 致命错误(exit):路径不存在、无权限读取根目录、参数无效 - 可恢复错误(warn):子目录无权限、符号链接循环、单个文件读取失败 - 所有警告输出到 stderr,不污染 stdout --- ## 6. 接口定义 ### 6.1 模块间数据流 ``` parse_args → TARGET_PATH, OUTPUT_FILE, MAX_DEPTH, SHOW_FILES ↓ load_ignore_config → IGNORE_PATTERNS[] ↓ traverse_directory + should_ignore → TREE_NODES, TREE_CHILDREN ↓ render_tree (F016) + render_file_list (F017) → 格式化字符串 ↓ ┌───────────────────┬────────────────────┐ ↓ ↓ ↓ output_terminal save_markdown compute_stats (F018) (F019) (F020) ↓ ↓ ↓ 终端显示 tree_output.md 统计信息追加 ``` ### 6.2 全局变量定义 ```bash TARGET_PATH="" # 目标目录路径(绝对路径) OUTPUT_FILE="tree_output.md" # 输出文件路径 MAX_DEPTH="" # 最大递归深度(空=无限制) SHOW_FILES=false # 是否生成文件树 SHOW_STATS=true # 是否显示统计信息 IGNORE_PATTERNS=() # 忽略模式数组 declare -A TREE_NODES # 节点存储 declare -A TREE_CHILDREN # 子节点关系 NODE_COUNTER=0 # 节点计数器 DIR_COUNT=0 # 目录计数 FILE_COUNT=0 # 文件计数 TOTAL_SIZE=0 # 总大小(字节) ``` ### 6.3 函数签名 - `parse_args()` → void - `load_ignore_config()` → void - `should_ignore(name)` → boolean - `traverse_directory(path, parent_id, depth)` → void - `render_tree(root_id, prefix)` → string - `collect_files(path)` → string[] - `render_file_list(files)` → string - `output_terminal(tree_str, file_str, stats_str)` → void - `save_markdown(tree_str, file_str, stats_str, output_path)` → void - `compute_stats()` → string - `normalize_path(path)` → string - `format_size(bytes)` → string --- ## 7. 脚本主体结构 ```bash #!/usr/bin/env bash set -euo pipefail # 常量定义 # 全局变量 # 工具函数(normalize_path, format_size, usage) # 核心模块(10个函数) # 主流程 main() main() { parse_args "$@" load_ignore_config traverse_directory "$TARGET_PATH" "root" 0 tree_output=$(render_tree "root" "") if $SHOW_FILES; then file_output=$(render_file_list "$(collect_files "$TARGET_PATH")") fi if $SHOW_STATS; then stats_output=$(compute_stats) fi output_terminal "$tree_output" "$file_output" "$stats_output" save_markdown "$tree_output" "$file_output" "$stats_output" } main "$@" ``` --- ## 8. 验收标准对照 - F013 接收路径输入 — 能正确解析相对路径和绝对路径 → normalize_path() + getopts ✅ - F014 加载忽略配置 — 支持.git、node_modules、__pycache__等 → 内置默认 + .treeignore 双层配置 ✅ - F015 递归遍历目录 — 能正确跳过忽略的目录 → should_ignore() + 递归遍历 ✅ - F016 生成目录树 — 使用├── ├──字符,缩进正确 → render_tree() 严格格式规范 ✅ - F017 生成文件树 — 每个文件带完整路径 → collect_files() + render_file_list() ✅ - F018 终端输出 — 终端显示格式正确 → printf + 彩色支持 ✅ - F019 Markdown 保存 — 默认保存到 tree_output.md → save_markdown() 代码块格式 ✅ - F020 统计信息 — 统计信息准确 → compute_stats() 目录/文件/大小 ✅ --- ## 9. 风险与约束 - Bash 4.0 以下版本不支持关联数组 — 脚本头部版本检查,给出明确提示 - 超大目录遍历性能 — 支持 --depth 限制深度 - 文件名含特殊字符 — 使用 printf '%s' 安全输出 - macOS du 与 Linux 差异 — 统一使用字节数后格式化 - 符号链接循环 — inode 检测 + 已访问集合 --- ## 10. 后续计划 1. T021 Shell 代码编写(待本方案审批通过后激活) 2. T022 功能测试验证 3. T024 使用文档编写 --- *文档结束*