云服务器上使用 Ubuntu 命令

  1. 查看磁盘占用情况,从小到大排序
bash 复制代码
du --max-depth=1 -h | sort -h
  1. 将当前目录下的内容全部打包
bash 复制代码
tar -cvf download.tar .
  1. 划定基线的打包程序 tar.py
python 复制代码
#!/usr/bin/env python3

"""

按大小过滤的打包脚本

用法: python tar.py [--max=200] [--path=path/] [--zip]

功能: 将目标目录打包为 tar 或 tar.gz,如果指定了 --max,则排除单个文件大小超过该阈值的文件。

"""



import os

import sys

import tarfile

import argparse

from pathlib import Path



# 尝试导入 tqdm,如果失败则使用自定义简单进度条

try:

    from tqdm import tqdm

    HAS_TQDM = True

except ImportError:

    HAS_TQDM = False

    # 自定义简单进度条

    def simple_progress_bar(iterable, total, desc="进度"):

        """

        简单的文本进度条实现

        """

        bar_len = 40

        sys.stdout.write(f"{desc}: 0%")

        sys.stdout.flush()

        for i, item in enumerate(iterable, 1):

            yield item

            if i % max(1, total // 100) == 0 or i == total:

                percent = i / total

                filled = int(bar_len * percent)

                bar = '█' * filled + '-' * (bar_len - filled)

                sys.stdout.write(f'\r{desc}: |{bar}| {percent*100:.1f}% ({i}/{total})')

                sys.stdout.flush()

        sys.stdout.write('\n')



def get_total_files_and_size(src_dir):

    """

    遍历目录,统计总文件数和总大小(用于进度条估算)

    返回: (总文件数, 总字节数)

    """

    total_files = 0

    total_size = 0

    for root, dirs, files in os.walk(src_dir):

        for file in files:

            file_path = os.path.join(root, file)

            try:

                total_size += os.path.getsize(file_path)

                total_files += 1

            except OSError:

                pass

    return total_files, total_size



def should_include(file_path, max_size_bytes):

    """

    判断文件是否应该被打包。

    返回 True 表示打包,False 表示跳过。

    """

    if os.path.isdir(file_path):

        return True

    try:

        file_size = os.path.getsize(file_path)

        if max_size_bytes is not None and file_size > max_size_bytes:

            return False

    except OSError:

        return False

    return True



def main():

    parser = argparse.ArgumentParser(

        description="打包目录,可选择跳过超过指定大小的文件"

    )

    parser.add_argument(

        "--max",

        type=int,

        default=None,

        help="文件大小阈值,单位 MB,例如 200 表示 200MB。缺省时不限制大小。"

    )

    parser.add_argument(

        "--path",

        type=str,

        default=".",

        help="要打包的目标目录路径,缺省为当前目录"

    )

    parser.add_argument(

        "--zip",

        "-z",

        action="store_true",

        help="开启 gzip 压缩,输出 .tar.gz 格式 (默认输出 .tar,不压缩)"

    )

    args = parser.parse_args()



    src_dir = os.path.abspath(args.path)

    if not os.path.isdir(src_dir):

        print(f"错误: 路径 '{src_dir}' 不是有效的目录")

        sys.exit(1)



    max_bytes = args.max * 1024 * 1024 if args.max is not None else None



    dir_name = os.path.basename(src_dir.rstrip('/\\'))

   

    # 根据是否压缩决定输出文件名和打开模式

    if args.zip:

        output_filename = f"{dir_name}_filtered.tar.gz" if args.max is not None else f"{dir_name}.tar.gz"

        tar_mode = "w:gz"  # gzip 压缩

        compress_desc = "gzip 压缩"

    else:

        output_filename = f"{dir_name}_filtered.tar" if args.max is not None else f"{dir_name}.tar"

        tar_mode = "w"  # 不压缩

        compress_desc = "不压缩"

   

    output_path = os.path.join(os.getcwd(), output_filename)



    print(f"目标目录: {src_dir}")

    if max_bytes is not None:

        print(f"阈值: {args.max} MB ({max_bytes} bytes)")

    else:

        print("阈值: 无限制 (打包所有文件)")

    print(f"压缩: {compress_desc}")

    print(f"输出文件: {output_path}")



    # 统计总文件数和总大小(用于进度条估算)

    print("正在扫描目录...")

    total_files, total_size = get_total_files_and_size(src_dir)

    print(f"总文件数: {total_files}, 总大小: {total_size/(1024*1024):.2f} MB")



    skipped_count = 0

    skipped_size = 0



    try:

        with tarfile.open(output_path, tar_mode) as tar:

            # 准备文件列表(用于进度条遍历)

            file_list = []

            for root, dirs, files in os.walk(src_dir):

                for file in files:

                    file_list.append(os.path.join(root, file))



            # 根据是否安装 tqdm 选择进度条实现

            if HAS_TQDM:

                print("使用 tqdm 进度条")

                iterator = tqdm(file_list, desc="打包进度", unit="file")

            else:

                print("使用标准进度条 (提示: 安装 tqdm 获得更美观的进度条: pip install tqdm)")

                iterator = simple_progress_bar(file_list, total=len(file_list), desc="打包进度")



            for file_path in iterator:

                arcname = os.path.relpath(file_path, start=os.path.dirname(src_dir))

                if should_include(file_path, max_bytes):

                    try:

                        if HAS_TQDM:

                            iterator.set_postfix_str(f"当前: {os.path.basename(file_path)}")

                        tar.add(file_path, arcname=arcname)

                    except Exception as e:

                        print(f"\n警告: 添加文件失败 {file_path}: {e}")

                else:

                    skipped_count += 1

                    try:

                        skipped_size += os.path.getsize(file_path)

                    except OSError:

                        pass



        print(f"\n打包完成: {output_path}")

        if skipped_count > 0:

            print(f"跳过了 {skipped_count} 个文件,总计 {skipped_size/(1024*1024):.2f} MB")

    except Exception as e:

        print(f"打包失败: {e}")

        sys.exit(1)



if __name__ == "__main__":

    main()
  1. 文件递归排序 filesize_sort.py
python 复制代码
#!/usr/bin/env python3

"""

文件大小排序工具

遍历指定目录,按文件大小从大到小排序并输出路径、大小和累积百分比

用法: python filesize_sort.py [--path=path/] [--top=N] [--reverse]

"""



import os

import sys

import argparse

from pathlib import Path



def human_readable_size(size_bytes):

    """

    将字节数转换为人类可读的格式(KB, MB, GB)

    返回格式: "1.23 GB"

    """

    if size_bytes == 0:

        return "0 B"

   

    units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

    unit_index = 0

   

    temp = size_bytes

    while temp >= 1024 and unit_index < len(units) - 1:

        temp /= 1024

        unit_index += 1

   

    if unit_index == 0:

        return f"{size_bytes} B"

    else:

        return f"{temp:.2f} {units[unit_index]}"



def get_file_info(src_dir, exclude_dirs=None):

    """

    遍历目录,收集所有文件的信息(路径和大小)

    """

    if exclude_dirs is None:

        exclude_dirs = []

   

    file_list = []

    src_dir = os.path.abspath(src_dir)

   

    if not os.path.isdir(src_dir):

        print(f"错误: 路径 '{src_dir}' 不是有效的目录")

        sys.exit(1)

   

    for root, dirs, files in os.walk(src_dir):

        dirs[:] = [d for d in dirs if d not in exclude_dirs]

       

        for file in files:

            file_path = os.path.join(root, file)

            try:

                size = os.path.getsize(file_path)

                file_list.append((file_path, size))

            except OSError:

                print(f"警告: 无法读取文件大小,跳过: {file_path}")

   

    return file_list



def main():

    parser = argparse.ArgumentParser(

        description="遍历目录,按文件大小排序输出,含累积百分比"

    )

    parser.add_argument(

        "--path",

        type=str,

        default=".",

        help="要遍历的目标目录路径,缺省为当前目录"

    )

    parser.add_argument(

        "--top",

        type=int,

        default=None,

        help="只显示前 N 个最大的文件"

    )

    parser.add_argument(

        "--reverse",

        "-r",

        action="store_true",

        help="按从小到大排序(默认从大到小)"

    )

    parser.add_argument(

        "--exclude",

        type=str,

        nargs="*",

        default=[".git", "__pycache__", "node_modules", ".idea", ".vscode"],

        help="要排除的目录名称(空格分隔),缺省排除常见缓存目录"

    )

    parser.add_argument(

        "--bytes",

        "-b",

        action="store_true",

        help="以字节数显示(不转换为 KB/MB/GB)"

    )

    parser.add_argument(

        "--no-percent",

        action="store_true",

        help="不显示累积百分比列"

    )

    args = parser.parse_args()



    src_dir = os.path.abspath(args.path)

   

    print(f"正在扫描目录: {src_dir}")

    print(f"排除目录: {args.exclude if args.exclude else '无'}")

   

    file_list = get_file_info(src_dir, args.exclude)

   

    if not file_list:

        print("没有找到任何文件")

        return

   

    # 按文件大小排序(默认从大到小)

    reverse_sort = not args.reverse

    file_list.sort(key=lambda x: x[1], reverse=reverse_sort)

   

    total_size = sum(size for _, size in file_list)

   

    # 如果指定了 --top,只取前 N 个

    display_list = file_list[:args.top] if args.top is not None else file_list

   

    print("\n" + "=" * 100)

   

    # 计算列宽

    max_path_len = max(len(path) for path, _ in display_list) if display_list else 0

    max_path_len = min(max_path_len, 50)

   

    # 根据是否显示百分比决定列头

    if args.no_percent:

        header = f"{'文件路径':<{max_path_len}}  {'大小':>15}"

    else:

        header = f"{'文件路径':<{max_path_len}}  {'大小':>15}  {'累积占比':>12}"

   

    print(header)

    print("-" * 100)

   

    # 累积大小(从大到小累加)

    cumulative_size = 0

   

    for idx, (file_path, size) in enumerate(display_list):

        cumulative_size += size

       

        # 显示路径(如果太长则截断)

        display_path = file_path if len(file_path) <= max_path_len else "..." + file_path[-(max_path_len-3):]

       

        # 格式化大小

        if args.bytes:

            size_str = f"{size:,} B"

        else:

            size_str = human_readable_size(size)

       

        # 计算累积百分比

        if args.no_percent:

            print(f"{display_path:<{max_path_len}}  {size_str:>15}")

        else:

            cum_percent = (cumulative_size / total_size) * 100 if total_size > 0 else 0

            # 如果当前文件是最后一个,百分比应为100%

            if idx == len(display_list) - 1:

                cum_percent = 100.0

            print(f"{display_path:<{max_path_len}}  {size_str:>15}  {cum_percent:>11.2f}%")

   

    print("-" * 100)

   

    # 统计信息

    if args.bytes:

        total_str = f"{total_size:,} B"

    else:

        total_str = human_readable_size(total_size)

   

    displayed_count = len(display_list)

    total_count = len(file_list)

   

    if args.top is not None:

        print(f"显示: {displayed_count}/{total_count} 个文件, 总大小: {total_str}")

        if not args.no_percent and display_list:

            # 显示前 N 个文件的占比

            top_percent = (cumulative_size / total_size) * 100

            print(f"前 {displayed_count} 个文件占总大小的: {top_percent:.2f}%")

    else:

        print(f"总计: {displayed_count} 个文件, 总大小: {total_str}")



if __name__ == "__main__":

    main()