AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 478977
Accepted
A. Donda
A. Donda
Asked: 2018-11-01 12:02:12 +0800 CST2018-11-01 12:02:12 +0800 CST 2018-11-01 12:02:12 +0800 CST

文件夹对磁盘使用的独特贡献

  • 772

我有一个包含每日快照文件夹的备份。为了节省空间,不同快照中的相同文件通过硬链接(由 rsync 生成)进行重复数据删除。

当空间不足时,一种选择是删除旧快照。但是由于硬链接,很难计算出删除给定快照会获得多少空间。

我能想到的一个选择是du -s首先在所有快照文件夹上使用,然后在除了我可能删除的文件夹之外的所有文件夹上使用,并且差异会给我预期的获得空间。但是,这非常麻烦,并且在我试图找到合适的快照进行删除时必须重复进行。

有没有更简单的方法?


在尝试并思考Stéphane Chazelas和derobert的答案后,我意识到我的问题不够精确。这是更精确的尝试:

我有一组目录(“快照”),其中包含与另一个快照中的文件部分存储相同(硬链接)的文件。我正在寻找一种解决方案,该解决方案可为我提供快照列表以及其中文件占用的每个已用磁盘存储量,但没有该存储也被另一个快照中的文件使用。我想允许每个快照中存在硬链接的可能性。

我的想法是我可以查看该列表来决定当我用完空间时我应该删除哪些快照,这是在删除获得的存储空间和快照的价值(例如基于年龄)之间的权衡。

disk-usage hard-link
  • 3 3 个回答
  • 335 Views

3 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-11-01T13:54:12+08:002018-11-01T13:54:12+08:00

    您可以使用 GNU 手动完成find:

    find snapshot-dir -type d -printf '1 %b\n' -o -printf '%n %b %i\n' |
       awk '$1 == 1 || ++c[$3] == $1 {t+=$2;delete c[$3]}
       END{print t*512}'
    

    这计算了在找到快照目录中找到的所有链接后链接计数将下降到 0 的文件的磁盘使用情况。

    find印刷:

    • 1 <disk-usage>对于目录
    • <link-count> <disk-usage> <inode-number>对于其他类型的文件。

    我们假装目录的链接计数总是一个,因为实际上它不是,这是因为..条目,并且find没有列出这些条目,目录通常没有其他硬链接。

    从该输出中,awk计算链接计数为 1 的条目的磁盘使用情况以及它看到的 inode 的磁盘使用情况<link-count>(即所有硬链接都在当前目录中的 inode,就像那些带有链接的 inode 一样) -count of one 将在删除目录树后回收其空间)。

    您还可以使用它find snapshot-dir1 snapshot-dir2来找出如果两个目录都被删除将回收多少磁盘空间(如果在两个目录中都找到了文件并且仅在那些快照)。

    如果你想知道每次删除快照目录后你会节省多少空间(以累积的方式),你可以这样做:

    find snapshot-dir* \( -path '*/*' -o -printf "%p:\n" \) \
      -type d -printf '1 %b\n' -o -printf '%n %b %i\n' |
       awk '/:$/ {if (NR>1) print t*512; printf "%s ", $0; next}
            $1 == 1 || ++c[$3] == $1 {t+=$2;delete c[$3]}
            END{print t*512}'
    

    它按词法顺序处理快照列表。如果您以不同的顺序处理它,那可能会给您不同的数字,除了最后一个(当所有快照都被删除时)。

    请参见numfmt使数字更具可读性。

    假设所有文件都在同一个文件系统上。如果没有,您可以替换%i为%D:%i(如果它们不在同一个文件系统上,那将意味着您在那里有一个无论如何都无法删除的挂载点)。

    • 2
  2. derobert
    2018-11-01T12:33:09+08:002018-11-01T12:33:09+08:00

    如果您的文件名不包含模式字符或换行符,您可以使用find+du的排除功能来执行此操作:

    find -links +1 -type f \
        | cut -d/ -f2- \
        | du --exclude-from=- -s *
    

    该find位获取-type f硬链接计数大于 1 ( ) 的所有文件 ( -links +1)。打印出cut领先发现的修剪。./然后du询问每个目录的磁盘使用情况,不包括具有多个链接的所有文件。当然,一旦您删除快照,现在可能只有一个链接的文件以前有两个 - 所以每删除几次,您真的应该重新运行它。

    如果它需要使用任意文件名,它需要更多的脚本来替换du(那些是 shell 模式,所以转义是不可能的)。

    此外,正如 Stéphane Chazelas 指出的那样,如果一个快照中存在硬链接(文件的所有名称都位于单个快照中,而不是快照之间的硬链接),这些文件将被排除在总数之外(即使删除快照会恢复那个空间)。

    • 1
  3. A. Donda
    2018-11-18T17:33:24+08:002018-11-18T17:33:24+08:00

    自从我写下这个答案以来,Stéphane Chazelas 一直让我相信他的答案是正确的。我留下了我的答案,包括代码,因为它也能很好地工作,并提供一些漂亮的打印。它的输出如下所示:

                  total               unique
    --T---G---M---k---B  --T---G---M---k---B
         91,044,435,456          665,754,624  back-2018-03-01T06:00:01
         91,160,015,360          625,541,632  back-2018-04-01T06:00:01
         91,235,970,560          581,360,640  back-2018-05-01T06:00:01
         91,474,846,208          897,665,536  back-2018-06-01T06:00:01
         91,428,597,760          668,853,760  back-2018-07-01T06:00:01
         91,602,767,360          660,594,176  back-2018-08-01T06:00:01
         91,062,218,752        1,094,236,160  back-2018-09-01T06:00:01
        230,810,647,552       50,314,291,712  back-2018-11-01T06:00:01
        220,587,811,328          256,036,352  back-2018-11-12T06:00:01
        220,605,425,664          267,876,352  back-2018-11-13T06:00:01
        220,608,163,328          268,711,424  back-2018-11-14T06:00:01
        220,882,714,112          272,000,000  back-2018-11-15T06:00:01
        220,882,118,656          263,202,304  back-2018-11-16T06:00:01
        220,882,081,792          263,165,440  back-2018-11-17T06:00:01
        220,894,113,280          312,208,896  back-2018-11-18T06:00:01
    

    由于我对这两个答案中的任何一个都不是 100% 满意(截至 2018 年 11 月 18 日)——尽管我从他们两个那里学到了东西——我创建了自己的工具并在此处发布。

    类似于Stéphane Chazelas的回答,它用于find获取 inode 列表和相关文件/目录大小,但不依赖于“最多一个链接”启发式。相反,它为每个输入目录创建一个唯一的索引节点列表(不是文件/目录!),从其他目录中过滤掉索引节点,然后将剩余的索引节点大小相加。这样它就可以解释每个输入目录中可能存在的硬链接。作为副作用,它忽略了来自输入目录集之外的可能的硬链接。

    使用的 bash 外部工具:find, xargs, mktemp, sort, tput, awk, tr, numfmt, touch, cat, comm, rm. 我知道,它不完全是轻量级的,但它完全符合我的要求。我在这里分享它以防其他人有类似的需求。

    如果有什么可以做得更高效或更简单的,欢迎评论!我不是 bash 大师。

    要使用它,请将以下代码保存到脚本文件duu.sh中。第一个注释块中包含简短的使用说明。

    #!/bin/bash
    
    # duu
    #
    # disk usage unique to a directory within a set of directories
    #
    # Call with a list of directory names. If called without arguments,
    # it operates on the subdirectories of the current directory.
    
    
    # no arguments: call itself with subdirectories of .
    if [ "$#" -eq 0 ]
    then
        exec find . -maxdepth 1 -type d ! -name . -printf '%P\0' | sort -z \
            | xargs -r --null "$0"
        exit
    fi
    
    
    # create temporary directory
    T=`mktemp -d`
    # array of directory names
    dirs=("$@")
    # number of directories
    n="$#"
    
    # for each directory, create list of (unique) inodes with size
    for i in $(seq 1 $n)
    do
        echo -n "reading $i/$n: ${dirs[$i - 1]} "
        find "${dirs[$i - 1]}" -printf "%i\t%b\n" | sort -u > "$T/$i"
        # find %b: "The amount of disk space used for this file in 512-byte blocks."
        echo -ne "\r"
        tput el
    done
    
    # print header
    echo "              total               unique"
    echo "--T---G---M---k---B  --T---G---M---k---B"
    
    # for each directory
    for i in $(seq 1 $n)
    do
        # compute and print total size
        #   sum block sizes and multiply by 512
        awk '{s += $2} END{printf "%.0f", s * 512}' "$T/$i" \
            | tr -d '\n' \
            | numfmt --grouping --padding 19
        echo -n "  "
    
        # compute and print unique size
        #   create list of (unique) inodes in the other directories
        touch "$T/o$i"
        for j in $(seq 1 $n)
        do
            if [ "$j" -ne "$i" ]
            then
                cat "$T/$j" >> "$T/o$i"
            fi
        done
        sort -o "$T/o$i" -u "$T/o$i"
        #   create list of (unique) inodes that are in this but not in the other directories
        comm -23 "$T/$i" "$T/o$i" > "$T/u$i"
        #   sum block sizes and multiply by 512
        awk '{s += $2} END{printf "%.0f", s * 512}' "$T/u$i" \
            | tr -d '\n' \
            | numfmt  --grouping --padding 19
        #   append directory name
        echo "  ${dirs[$i - 1]}"
    done
    
    # remove temporary files
    rm -rf "$T"
    
    • 0

相关问题

  • 使用 DD 在外部读取器中写入原始磁盘时出现磁盘空间错误?

  • 如何提高磁盘空间使用率?

  • ln 中带有硬链接和软链接的路径

  • 具有更细粒度的人类可读的“du”

  • 除了完全使用的文件夹之外,“设备上没有剩余空间”的其他原因是什么?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve