tree.sh — 目录树生成脚本
一个用纯 Bash 编写的轻量级目录树生成工具,支持忽略配置、递归遍历、文件列表、Markdown 导出和统计信息。无需安装任何依赖,开箱即用。
版本: 1.0.0
功能特性
| 功能 | 说明 |
|---|---|
| 目录树生成 | 使用 ├── / └── 字符生成标准树形结构,目录在前、文件在后,按字母排序 |
| 文件列表 | 可选生成完整文件列表(-f),显示所有文件的绝对路径 |
| 忽略配置 | 内置 30+ 种常见忽略模式(.git、node_modules、__pycache__ 等),支持 .treeignore 自定义 |
| 深度限制 | 通过 -d 参数限制递归深度,避免过深遍历 |
| Markdown 导出 | 默认保存为 tree_output.md,也可自定义输出路径 |
| 统计信息 | 自动统计目录数、文件数和总大小(自动转换为 B / KB / MB / GB) |
| 循环检测 | 基于 inode 检测符号链接循环,防止无限递归 |
| 权限处理 | 对无权限目录显示 [Permission denied],不会中断执行 |
环境要求
- 操作系统: Linux 或 macOS
- Shell: Bash 4.0 或更高版本
- 依赖: 无(仅使用 Bash 内置命令和
stat、awk、basename、dirname、mkdir等标准工具)
检查 Bash 版本:
bash --version
安装方法
零安装。 直接下载或克隆脚本后即可运行:
chmod +x tree.sh
./tree.sh -p /path/to/target
也可以将脚本放到 PATH 中的某个目录,方便全局调用:
sudo cp tree.sh /usr/local/bin/tree.sh
tree.sh -p /path/to/target
使用方法
基本用法
# 生成当前目录的树形结构
./tree.sh
# 生成指定目录的树形结构
./tree.sh -p /home/user/project
# 使用相对路径
./tree.sh -p ../some-project
命令行选项
| 选项 | 简写 | 说明 | 默认值 |
|---|---|---|---|
--path <路径> |
-p |
指定目标目录 | 当前目录 (.) |
--output <文件> |
-o |
指定 Markdown 输出文件 | tree_output.md |
--depth <N> |
-d |
限制递归深度(正整数) | 无限制 |
--files |
-f |
同时生成文件列表 | 关闭 |
--no-stats |
-s |
不显示统计信息 | 显示 |
--help |
-h |
显示帮助信息 | — |
--version |
-v |
显示版本信息 | — |
常用示例
# 生成当前目录的完整树(含文件列表和统计)
./tree.sh -f
# 只查看前 2 层目录结构
./tree.sh -d 2
# 生成项目树并保存到自定义文件
./tree.sh -p /var/www/myapp -o project-tree.md
# 深度 3 + 文件列表 + 保存
./tree.sh -p ./src -d 3 -f -o src-tree.md
# 仅终端输出,不保存 Markdown 文件(重定向)
./tree.sh -p . -s > /dev/null
# 查看帮助
./tree.sh -h
# 查看版本
./tree.sh -v
配置说明
内置忽略列表
脚本默认忽略以下目录和文件类型:
版本控制:
.git、.svn、.hg
包管理 & 缓存:
node_modules、__pycache__、.cache、.tox、.eggs
构建产物:
dist、build、.next、.nuxt、.output、.vercel、.terraform、.vagrant
IDE & 编辑器:
.idea、.vscode
编译产物:
*.pyc、*.pyo、*.egg-info、*.swp、*.swo、*.swn、*.class、*.o、*.so、*.dylib
系统文件:
.DS_Store
自定义忽略配置
在目标目录下创建 .treeignore 文件,每行一个忽略模式:
# .treeignore 示例
# 注释以 # 开头
# 忽略特定目录
logs
tmp
*.log
# 忽略特定文件类型
*.bak
*.tmp
*.orig
# 忽略特定名称
.env.local
coverage
规则:
- 空行和以
#开头的行会被忽略(作为注释) - 支持精确匹配(如
logs)和 glob 通配符(如*.log) - 忽略模式会追加到内置列表之后,不会覆盖内置规则
使用示例
示例 1:基本目录树
$ ./tree.sh -p ./my-project
终端输出:
my-project/
├── src/
│ ├── main.sh
│ ├── utils/
│ │ ├── helpers.sh
│ │ └── validators.sh
│ └── config.sh
├── tests/
│ ├── test_main.sh
│ └── test_utils.sh
├── README.md
└── tree_output.md
Files:
/home/user/my-project/src/main.sh
/home/user/my-project/src/utils/helpers.sh
/home/user/my-project/src/utils/validators.sh
/home/user/my-project/src/config.sh
/home/user/my-project/tests/test_main.sh
/home/user/my-project/tests/test_utils.sh
/home/user/my-project/README.md
/home/user/my-project/tree_output.md
Statistics:
Directories: 4
Files: 8
Total size: 12.34 KB
示例 2:限制深度
$ ./tree.sh -p ./my-project -d 2
输出:
my-project/
├── src/
│ ├── main.sh
│ ├── utils/
│ └── config.sh
├── tests/
│ ├── test_main.sh
│ └── test_utils.sh
├── README.md
└── tree_output.md
示例 3:生成 Markdown 文件
$ ./tree.sh -p ./my-project -f -o my-tree.md
生成的 my-tree.md 内容:
# Directory Tree
Path: `./my-project`
my-project/ ├── src/ │ ├── main.sh │ ├── utils/ │ │ ├── helpers.sh │ │ └── validators.sh │ └── config.sh ├── tests/ │ ├── test_main.sh │ └── test_utils.sh ├── README.md └── tree_output.md
## Files
/home/user/my-project/src/main.sh
...
## Statistics
- **Directories:** 4
- **Files:** 8
- **Total size:** 12.34 KB
示例 4:结合 .treeignore 使用
# 创建 .treeignore
echo -e "*.log\ntmp\ncoverage" > .treeignore
# 运行脚本(自动加载 .treeignore)
./tree.sh -p .
注意事项
-
路径必须存在且为目录:如果指定的路径不存在或不是目录,脚本会报错退出(退出码 2)。
-
深度参数必须为正整数:
-d参数必须传入大于 0 的整数,否则报错退出(退出码 1)。 -
符号链接循环检测:脚本基于 inode 检测循环引用。如果检测到循环,会显示
[cycle detected, skipped]并跳过,不会无限递归。 -
权限问题:遇到无权限读取的目录时,会显示
[Permission denied]并继续处理其他目录,不会中断整个流程。 -
输出文件目录自动创建:如果
-o指定的输出路径中的目录不存在,脚本会自动创建。 -
Markdown 文件始终生成:脚本每次运行都会同时输出到终端和保存 Markdown 文件(默认
tree_output.md)。终端输出和 Markdown 内容一致。 -
大小写敏感:忽略模式匹配区分大小写。
-
隐藏文件:以
.开头的隐藏文件/目录会被正常遍历(除非被忽略规则匹配)。 -
退出码:
0:成功1:参数错误2:路径无效3:写入失败
项目信息
- 项目 ID: PROJ-20260509011
- 功能覆盖: F013–F020(8 个功能全部测试通过)