Hexo

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

Mac——查看文件占用情况


整体说明

  • 快速查看非隐藏第一层目录大小:du -sh */
  • 包含隐藏目录:find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \;
  • 按大小排序:在上述命令后加 | sort -hr
  • 查看逻辑大小(对应稀疏文件):du -shL */

最常用:显示第一层目录大小(人类可读格式,如 M/G)

  • 命令详情:

    1
    du -sh */
  • 命令解释:

    • du:统计目录/文件的磁盘占用;
    • -s(--summarize):只显示总大小(不列出子文件/子目录的详细大小);
    • -h(--human-readable):用人类易读的单位(K/M/G)显示;
    • */:通配符,只匹配当前目录下的「第一层子目录」(结尾的 / 是关键,排除文件,只选目录);
  • 简单直接,默认显示「实际磁盘占用」(和 Linux du -sh */ 逻辑一致),适合快速查看


精准筛选第一层目录(避免通配符遗漏,如隐藏目录)

  • */ 会匹配所有非隐藏的第一层目录,但如果有「隐藏目录」(如 .hidden_dir),会被遗漏

  • 如果需要包含隐藏目录,用 find 筛选第一层目录,再传递给 du:

    1
    2
    # 包含隐藏目录的第一层目录大小(人类可读)
    find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \;
  • 命令解释:

    • find .:从当前目录(.)开始查找;
    • -maxdepth 1:只查找「第一层」(不递归子目录);
    • -type d:只匹配目录(排除文件);
    • ! -name ".":排除当前目录本身(只保留子目录);
    • -exec du -sh {} \;:对找到的每个目录,执行 du -sh 统计总大小;

按大小排序(方便找出最大目录)

  • 如果想按目录大小「从大到小排序」,结合 sort 命令(Mac 自带 BSD sort,参数和 Linux 略有差异):

    1
    2
    3
    4
    5
    # 第一层目录大小(非隐藏),按大小降序排序
    du -sh */ | sort -hr

    # 包含隐藏目录,按大小降序排序
    find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \; | sort -hr
  • 命令解释:

    • sort -hr:-h 识别人类可读单位(如 M/G),-r 反向排序(从大到小);

显示「逻辑大小」(而非磁盘占用,对应稀疏文件场景)

  • 如果想查看目录的「逻辑总大小」(而非磁盘占用,和 ls 统计逻辑一致),用 du -shL */:

    1
    2
    # 第一层目录的逻辑总大小(人类可读)
    du -shL */
  • 命令解释:

    • -L(--dereference):跟随符号链接,并统计链接指向文件的「逻辑大小」(而非磁盘占用);
    • 适合用于确认目录的逻辑总数据量(比如对比 Linux 上的逻辑大小)

关键补充:Mac 和 Linux 的 du 差异

  • 单位一致性:-h 参数在 Mac 和 Linux 上行为一致(K/M/G 单位);
  • 隐藏目录:Mac 上 */ 不匹配隐藏目录,需用 find 命令包含;
  • 稀疏文件:Mac 上 du 默认统计「实际磁盘占用」,如果目录内有稀疏文件(未展开),du -sh 显示实际占用,du -shL 显示逻辑大小

统计一个文件夹下所有数据逻辑大小

  • 递归列出所有数据,加起来,并以 MB(兆字节)为单位输出(Mac 和 Linux 通用):

    1
    ls -lR ./ | awk '{sum += $5} END {print sum/1024/1024 "M"}'
  • 命令解释

    • ls -lR ./:递归输出当前目录下所有文件/目录的详细信息(作为数据源)
      • -R(recursive,递归):不仅列出当前目录的文件/目录,还会递归列出所有子目录下的文件/目录
      • 注意:不包括隐藏文件和文件夹,可以通过改为下面的指令来显示隐藏文件
        • ls -laR ./,包含 . 和 ..(ls -l 中目录的第5列是“目录元数据大小”(不是目录内文件总大小),数值极小,可以忽略)
        • ls -lAR ./,不包含 . 和 ..
    • awk '{sum += $5} END {print sum/1024/1024 "M"}':计算所有文件的逻辑大小总和,并转换为 MB 单位
      • awk 是文本处理工具,这里用于“提取第5列的字节数,求和后转换为 MB”:
      • 循环累加({sum += $5}):
        • $5:表示取每一行的「第5个字段」(awk 中用 $n 表示第n个字段,字段默认用空格分隔)
        • sum += $5:定义一个变量 sum,把每一行第5列的数值(文件逻辑大小,字节)累加到 sum 中
        • 注意:目录的第5列(几十字节)也会被累加,但因为数值极小,对总结果几乎无影响(比如100个目录的元数据总和可能只有几 KB,相对于几百 MB 的文件总和可忽略)
      • 最终输出(END {print sum/1024/1024 "M"}):
        • END:表示“所有行都处理完后,执行以下操作”(仅执行一次)
        • sum/1024/1024:单位转换:字节 -> KB(除以1024)-> MB(再除以1024)
        • "M":拼接字符串,让输出结果带单位(比如 600M 而非纯数字)
        • print:输出最终结果

注意统计的是「逻辑大小」,不是「磁盘实际占用」

  • 逻辑大小:文件本身的“理论大小”(比如稀疏文件的预留空间、普通文件的实际数据大小),和 ls -lh 显示的大小一致;
  • 磁盘实际占用:文件在磁盘上真正占用的空间(比如稀疏文件的实际写入数据大小),需用 du 统计;
  • ls -l 中目录的第5列是“目录元数据大小”(不是目录内文件总大小),但因为数值极小(通常几十字节),累加后对总结果(几百 MB)几乎无影响,无需刻意排除

Pyhton——原生random模块的使用


整体说明

  • 随机种子(seed)是初始化随机数生成器的状态,相同种子产生完全相同的随机序列(可复现性)
    • 不设置种子时,使用系统时间(time.time())作为种子,每次运行结果不同
    • 种子可以是整数、字符串、字节等(内部会转换为整数)
  • 随机状态(state)本质是生成器的内部状态(包含所有必要信息,确保后续随机数可预测)
    • random.getstate():保存当前状态(返回一个元组)
    • random.setstate(state):恢复到之前保存的状态
  • 全局 random 模块在所有地方共享一个状态,不是线程安全的(多线程会竞争状态)
    • 建议多使用 局部 random.Random 实例而不是全局 random 模块

random 模块示例

  • 以下是一个原生的 Python random 模块使用示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    import random

    print("=" * 50)
    print("随机种子的可复现性演示")
    print("=" * 50)

    print("\n【不设置种子(全局随机)】")
    random.seed() # 重置为默认状态(系统时间种子)
    print(f"第一次随机整数序列: {[random.randint(1, 100) for _ in range(3)]}")
    print(f"第二次随机整数序列: {[random.randint(1, 100) for _ in range(3)]}")

    print("\n【设置固定种子】")
    random.seed(42) # 固定种子,注意 seed 是一个函数,不要写成 random.seed = 42,这样会导致 seed 失效
    print(f"种子42-序列: {[random.randint(1, 100) for _ in range(3)]}") # 结果为固定值,跨平台跨进程可复现

    random.seed(42) # 固定种子,重新设置相同种子,会重置随机序列到初始状态
    print(f"种子42-序列: {[random.randint(1, 100) for _ in range(3)]}") # 结果复现上面的结果

    print("\n" + "=" * 50)
    print("随机状态的保存与恢复")
    print("=" * 50)

    random.seed(100) # 先设置种子,确保初始状态一致
    print(f"\n初始状态-随机数序列: {[random.randint(1, 100) for _ in range(3)]}")

    state = random.getstate() # 保存当前随机状态(返回一个不可变对象,包含完整的随机生成器状态)
    print(f"状态改变后-随机数序列: {[random.randint(1, 100) for _ in range(3)]}") # 继续生成几个随机数

    random.setstate(state)# 恢复之前保存的状态,从当时状态开始继续除数,就像是 seed(100) 后已经输出过多个 随机数一样
    print(f"恢复状态后-随机数序列: {[random.randint(1, 100) for _ in range(3)]}") # 继续生成几个随机数,得到的结论是跟上面一致的

    print("\n" + "=" * 50)
    print("全局随机 vs 局部随机实例")
    print("=" * 50)

    # 全局 random:所有模块共享同一个状态
    print("\n【全局随机(共享状态)】")
    random.seed(200)
    print(f"全局-随机数1: {random.uniform(0, 10)}")
    print(f"全局-随机数2: {random.uniform(0, 10)}")

    # 局部 Random 实例:独立状态,不影响全局
    local_rand1 = random.Random(300) # 局部实例1,种子300
    local_rand2 = random.Random(300) # 局部实例2,种子300
    local_rand3 = random.Random(400) # 局部实例2,种子400

    print("\n【局部随机实例(独立状态)】")
    print(f"局部1-随机数(seed=300): {local_rand1.randint(1, 10)}")
    print(f"局部2-随机数(seed=300): {local_rand2.randint(1, 10)}")
    print(f"局部3-随机数(seed=400): {local_rand2.randint(1, 10)}")

    # ==================================================
    # 随机种子的可复现性演示
    # ==================================================
    #
    # 【不设置种子(全局随机)】
    # 第一次随机整数序列: [100, 29, 44]
    # 第二次随机整数序列: [16, 34, 5]
    #
    # 【设置固定种子】
    # 种子42-序列: [82, 15, 4]
    # 种子42-序列: [82, 15, 4]
    #
    # ==================================================
    # 随机状态的保存与恢复
    # ==================================================
    #
    # 初始状态-随机数序列: [19, 59, 59]
    # 状态改变后-随机数序列: [99, 23, 91]
    # 恢复状态后-随机数序列: [99, 23, 91]
    #
    # ==================================================
    # 全局随机 vs 局部随机实例
    # ==================================================
    #
    # 【全局随机(共享状态)】
    # 全局-随机数1: 0.4560930208539393
    # 全局-随机数2: 2.0344697486239927
    #
    # 【局部随机实例(独立状态)】
    # 局部1-随机数(seed=300): 10
    # 局部2-随机数(seed=300): 10
    # 局部3-随机数(seed=400): 6

附录:特别说明

  • random.seed 是一个函数而不是一个数字或字符串,需要使用 random.seed(1) 而不是 random.seed=1 来设置种子
    • 这里容易理解错误
  • 所有设置了固定种子的部分(如 seed=42、local_rand1 = random.Random(300)),每次运行结果完全一致
  • 全局随机在未设置种子时,每次运行结果不同;但恢复状态后,会延续之前的序列
  • 局部实例的操作不会影响全局或其他局部实例的状态,实现了完全隔离
  • random.shuffle(input) 是个 in-place 修改方法,会直接修改 input 对象的值

附录:random 隔离实用技巧

  • 临时固定状态:保存原始状态 -> 设置临时种子 -> 执行操作 -> 恢复原始状态(避免污染全局)
  • 独立随机流:为不同任务/模块分配独立种子(比如 task_seed = base_seed + task_id),确保并行任务结果可复现
  • 局部状态持久化:保存局部实例的状态(如 local_rand.getstate()),后续可在其他地方恢复继续使用
  • 禁止全局污染:封装局部实例,强制代码使用独立随机生成器(避免误改全局状态)
1…327328329…352
San Ye

San Ye

Stay Hungry. Stay Foolish.

704 posts
53 tags
© 2026 San Ye
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4