如何编写目录树生成脚本

wen 实用脚本 32

本文目录导读:

如何编写目录树生成脚本

  1. Python版本(功能最完整)
  2. Bash版本(简单实用)
  3. Node.js版本(跨平台)
  4. 使用示例
  5. 输出示例

我来教你编写目录树生成脚本,提供多个版本供你选择。

Python版本(功能最完整)

#!/usr/bin/env python3
"""
目录树生成脚本
支持文件/文件夹图标,过滤git等目录
"""
import os
import sys
from pathlib import Path
def generate_tree(directory, prefix="", show_hidden=False, max_depth=None, current_depth=0):
    """
    生成目录树结构
    """
    if max_depth is not None and current_depth > max_depth:
        return
    # 获取目录内容并排序
    try:
        entries = sorted(Path(directory).iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))
    except PermissionError:
        print(f"{prefix}└── [权限不足]")
        return
    # 过滤文件
    filtered_entries = []
    for entry in entries:
        name = entry.name
        # 跳过隐藏文件
        if not show_hidden and name.startswith('.'):
            continue
        # 跳过特定目录
        if name in ['__pycache__', 'node_modules', '.git', '.svn', '.DS_Store']:
            continue
        filtered_entries.append(entry)
    # 打印目录树
    for i, entry in enumerate(filtered_entries):
        is_last = (i == len(filtered_entries) - 1)
        connector = "└── " if is_last else "├── "
        if entry.is_dir():
            print(f"{prefix}{connector}{'📁 '}{entry.name}/")
            # 递归处理子目录
            extension = "    " if is_last else "│   "
            generate_tree(
                entry, 
                prefix + extension, 
                show_hidden, 
                max_depth, 
                current_depth + 1
            )
        else:
            # 显示文件大小
            try:
                size = entry.stat().st_size
                size_str = format_size(size)
                print(f"{prefix}{connector}{'📄 '}{entry.name} ({size_str})")
            except:
                print(f"{prefix}{connector}{'📄 '}{entry.name}")
def format_size(bytes):
    """格式化文件大小"""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if bytes < 1024:
            return f"{bytes:.1f} {unit}"
        bytes /= 1024
    return f"{bytes:.1f} TB"
def main():
    import argparse
    parser = argparse.ArgumentParser(description='生成目录树结构')
    parser.add_argument('directory', nargs='?', default='.', 
                       help='要分析的目录路径 (默认: 当前目录)')
    parser.add_argument('-a', '--all', action='store_true',
                       help='显示隐藏文件')
    parser.add_argument('-d', '--depth', type=int, default=None,
                       help='最大深度')
    parser.add_argument('-o', '--output', type=str,
                       help='输出到文件')
    parser.add_argument('--no-icon', action='store_true',
                       help='不显示图标')
    args = parser.parse_args()
    if not os.path.exists(args.directory):
        print(f"错误: 目录 '{args.directory}' 不存在")
        sys.exit(1)
    # 重定向输出到文件
    if args.output:
        import io
        old_stdout = sys.stdout
        sys.stdout = io.StringIO()
    print(f"📂 {os.path.abspath(args.directory)}/\n")
    generate_tree(args.directory, show_hidden=args.all, max_depth=args.depth)
    if args.output:
        with open(args.output, 'w', encoding='utf-8') as f:
            f.write(sys.stdout.getvalue())
        sys.stdout = old_stdout
        print(f"目录树已保存到: {args.output}")
if __name__ == "__main__":
    main()

Bash版本(简单实用)

#!/bin/bash
# tree.sh - 简易目录树生成脚本
# 使用tree命令(如果存在)
if command -v tree &> /dev/null; then
    tree -L ${1:-3} --charset utf-8
    exit 0
fi
# 自定义实现
list_files() {
    local dir="$1"
    local prefix="$2"
    local depth="${3:-0}"
    local max_depth="${4:-3}"
    if [ "$depth" -ge "$max_depth" ]; then
        return
    fi
    # 获取文件列表
    local files=("$dir"/*)
    local total=${#files[@]}
    local count=0
    for file in "${files[@]}"; do
        count=$((count + 1))
        local name=$(basename "$file")
        # 跳过隐藏文件和特定目录
        [[ "$name" == .* ]] && continue
        [[ "$name" == "node_modules" ]] && continue
        [[ "$name" == "__pycache__" ]] && continue
        if [ $count -eq $total ]; then
            echo "${prefix}└── $name"
            if [ -d "$file" ]; then
                list_files "$file" "${prefix}    " $((depth + 1)) $max_depth
            fi
        else
            echo "${prefix}├── $name"
            if [ -d "$file" ]; then
                list_files "$file" "${prefix}│   " $((depth + 1)) $max_depth
            fi
        fi
    done
}
# 主程序
ROOT_DIR="${1:-.}"
MAX_DEPTH="${2:-3}"
echo "📂 $(realpath "$ROOT_DIR")/"
list_files "$ROOT_DIR" "" 0 "$MAX_DEPTH"

Node.js版本(跨平台)

#!/usr/bin/env node
// tree.js - Node.js目录树生成
const fs = require('fs');
const path = require('path');
class DirectoryTree {
    constructor(options = {}) {
        this.showHidden = options.showHidden || false;
        this.maxDepth = options.maxDepth || Infinity;
        this.icons = options.icons !== false;
    }
    generate(dirPath, prefix = '', depth = 0) {
        if (depth > this.maxDepth) return;
        let entries;
        try {
            entries = fs.readdirSync(dirPath, { withFileTypes: true });
        } catch (err) {
            console.log(`${prefix}└── [${err.message}]`);
            return;
        }
        // 过滤和排序
        entries = entries
            .filter(entry => {
                if (!this.showHidden && entry.name.startsWith('.')) return false;
                if (['node_modules', '__pycache__', '.git'].includes(entry.name)) return false;
                return true;
            })
            .sort((a, b) => {
                if (a.isDirectory() && !b.isDirectory()) return -1;
                if (!a.isDirectory() && b.isDirectory()) return 1;
                return a.name.localeCompare(b.name);
            });
        entries.forEach((entry, index) => {
            const isLast = index === entries.length - 1;
            const connector = isLast ? '└── ' : '├── ';
            const icon = this.icons ? (entry.isDirectory() ? '📁 ' : '📄 ') : '';
            if (entry.isDirectory()) {
                console.log(`${prefix}${connector}${icon}${entry.name}/`);
                const extension = isLast ? '    ' : '│   ';
                this.generate(
                    path.join(dirPath, entry.name),
                    prefix + extension,
                    depth + 1
                );
            } else {
                const stats = fs.statSync(path.join(dirPath, entry.name));
                const size = this.formatSize(stats.size);
                console.log(`${prefix}${connector}${icon}${entry.name} (${size})`);
            }
        });
    }
    formatSize(bytes) {
        const units = ['B', 'KB', 'MB', 'GB'];
        let size = bytes;
        for (const unit of units) {
            if (size < 1024) return `${size.toFixed(1)} ${unit}`;
            size /= 1024;
        }
        return `${size.toFixed(1)} TB`;
    }
}
// 主程序
const args = process.argv.slice(2);
const dirPath = args[0] || '.';
const maxDepth = parseInt(args[1]) || 3;
const tree = new DirectoryTree({
    showHidden: args.includes('--all'),
    maxDepth: maxDepth,
    icons: !args.includes('--no-icon')
});
console.log(`📂 ${path.resolve(dirPath)}/\n`);
tree.generate(dirPath);

使用示例

Python版本:

# 基本使用
python tree.py
# 指定目录
python tree.py /path/to/directory
# 显示隐藏文件
python tree.py -a
# 限制深度
python tree.py -d 2
# 输出到文件
python tree.py -o output.txt
# 查看帮助
python tree.py -h

Bash版本:

# 添加执行权限
chmod +x tree.sh
# 使用(参数:目录 深度)
./tree.sh /path/to/directory 2

Node.js版本:

# 添加执行权限
chmod +x tree.js
# 使用
node tree.js /path/to/directory 2 --all

输出示例

📂 /home/user/project/
├── 📁 src/
│   ├── 📁 components/
│   │   ├── 📄 App.js (2.3 KB)
│   │   └── 📄 Header.js (1.1 KB)
│   ├── 📄 index.js (0.5 KB)
│   └── 📄 styles.css (3.2 KB)
├── 📁 public/
│   └── 📄 index.html (1.0 KB)
├── 📄 package.json (0.8 KB)
└── 📄 README.md (2.1 KB)

选择最适合你需求的版本,建议使用Python版本功能最完整,Bash版本最轻量,Node.js版本适合前端开发者。

抱歉,评论功能暂时关闭!