计算所有不可删除文件(包括子目录中的文件)的总大小
Calculate total size of all un-deletable files (including files in subdirectories)
我有一个有点奇怪的问题,服务器上有数百个用户的共享存储。我想识别我的用户无法删除的所有文件(if 我尝试 运行 自动删除脚本)。
对于所有这些已识别的文件,我需要长列表格式(即:完整路径、所有者、上次修改时间、大小)。我目前的理解是,这将是所有直接父目录对我来说不可写的文件,如果这种做法有误,请指正。
识别出这些文件后,我还需要获取它们占用的总大小。虽然,这一步也可以通过使用简单的 python 脚本来完成,也可以添加所有尺寸,但我仍在寻找是否有更好的方法。
这是我目前的做法:
find /downloads/ -type d ! -writable -print0 |
xargs -0 -I{.} find {.} -maxdepth 1 -type f -print0 |
xargs -0 -I{.} ls -l {.} > myfile.txt
- 查找我的用户不可写的所有目录(递归)
- 查找每个目录的所有直接子目录,并仅过滤掉文件。
- 获取每个已识别文件的长列表并将结果存储在 .txt 文件中
- 使用 python 读取此 .txt 文件并添加所有单独的大小(以字节为单位)以获得总大小。除以 (1024*1024*1024) 得到以 GB 为单位的大小。 (python 下面的脚本:)
with open("myfile.txt", "r") as f:
total_size = 0
for line in f:
try:
data = line.split()
if len(data) > 5:
total_size += int(data[4]) # "4" is the index of the size column
except:
pass
print("Total Size:", str(round(total_size/(1024*1024*1024), 2)), "GB")
我在使用这种方法时遇到的问题是,我得到的最终大小是整个卷的总大小。
My answer = 1400.02GB (as reported by following the steps above)
The total size of the entire shared space = 1400.02GB
Actual occupied space on the shared server = 800GB
Expected answer should be <800GB
所以你看到的问题是我的答案等于整个服务器的总大小space,包括甚至没有被占用的space。
我的答案 (1400.02GB) 与预期答案 (<800GB) 之间的这种不匹配也让我质疑已识别文件的正确性。
有人可以建议一个更好的方法来做到这一点,或者指出我的方法中的问题以便我可以解决它。非常感谢。
以下是为什么仅添加 ls
报告的字节数来计算磁盘使用率被认为是幼稚的两个原因:
- 你在重复计算硬链接文件,即使硬链接只是一个目录条目,基本上不占用额外的磁盘空间space。
- 如果您想找出实际的磁盘使用情况(“获取它们占用的总大小”),您必须考虑块大小。例如。一个包含 1000 个 1 字节文件的目录比一个包含一个 1MB 文件的目录
占用更多space
因此,适合这项工作的工具是 du
。但是为了 du
能够正确地完成他的工作而不是重复计算硬链接,您必须立即检查所有文件。幸运的是 du
的 GNU 版本有 --files0-from
选项,例如你可以使用
find . -type d ! -writable -print0 |
du -ch -d 1 --files0-from=- |
tail -n 1
这也避免了 xargs
由于 -I
选项可能会非常慢,这意味着您正在为每个参数执行 find
调用。
我不确定为什么你的命令给出了如此错误的数字,但这里有另一个你可以试试。
请注意,“它们占用的总大小” 可能与 ls
打印的大小总和有很大差异,这是由于文件系统块、硬链接等原因和稀疏文件。所以我们使用 du
而不是 ls
来获取尺寸。
下面的命令基本上是 ,但将 ls
合并到同一搜索中并使用 -exec +
而不是 xargs -I
,这应该会大大加快命令速度,因为你 运行 第二个 find
只用了几次而不是每个目录一次。
#! /bin/bash
longlist() {
ls -l "$@" >> "$longlistfile"
}
filesonly() {
find "$@" -maxdepth 1 -type f -exec bash -c 'longlist "$@"' . {} + -print0
}
export -f longlist filesonly
export longlistfile=myfile.txt
rm -f "$longlistfile"
find . -type d \! -writable -exec bash -c 'filesonly "$@"' . {} + |
du -ch --files0-from=- | tail -n1
我有一个有点奇怪的问题,服务器上有数百个用户的共享存储。我想识别我的用户无法删除的所有文件(if 我尝试 运行 自动删除脚本)。
对于所有这些已识别的文件,我需要长列表格式(即:完整路径、所有者、上次修改时间、大小)。我目前的理解是,这将是所有直接父目录对我来说不可写的文件,如果这种做法有误,请指正。
识别出这些文件后,我还需要获取它们占用的总大小。虽然,这一步也可以通过使用简单的 python 脚本来完成,也可以添加所有尺寸,但我仍在寻找是否有更好的方法。
这是我目前的做法:
find /downloads/ -type d ! -writable -print0 |
xargs -0 -I{.} find {.} -maxdepth 1 -type f -print0 |
xargs -0 -I{.} ls -l {.} > myfile.txt
- 查找我的用户不可写的所有目录(递归)
- 查找每个目录的所有直接子目录,并仅过滤掉文件。
- 获取每个已识别文件的长列表并将结果存储在 .txt 文件中
- 使用 python 读取此 .txt 文件并添加所有单独的大小(以字节为单位)以获得总大小。除以 (1024*1024*1024) 得到以 GB 为单位的大小。 (python 下面的脚本:)
with open("myfile.txt", "r") as f:
total_size = 0
for line in f:
try:
data = line.split()
if len(data) > 5:
total_size += int(data[4]) # "4" is the index of the size column
except:
pass
print("Total Size:", str(round(total_size/(1024*1024*1024), 2)), "GB")
我在使用这种方法时遇到的问题是,我得到的最终大小是整个卷的总大小。
My answer = 1400.02GB (as reported by following the steps above)
The total size of the entire shared space = 1400.02GB
Actual occupied space on the shared server = 800GB
Expected answer should be <800GB
所以你看到的问题是我的答案等于整个服务器的总大小space,包括甚至没有被占用的space。
我的答案 (1400.02GB) 与预期答案 (<800GB) 之间的这种不匹配也让我质疑已识别文件的正确性。
有人可以建议一个更好的方法来做到这一点,或者指出我的方法中的问题以便我可以解决它。非常感谢。
以下是为什么仅添加 ls
报告的字节数来计算磁盘使用率被认为是幼稚的两个原因:
- 你在重复计算硬链接文件,即使硬链接只是一个目录条目,基本上不占用额外的磁盘空间space。
- 如果您想找出实际的磁盘使用情况(“获取它们占用的总大小”),您必须考虑块大小。例如。一个包含 1000 个 1 字节文件的目录比一个包含一个 1MB 文件的目录 占用更多space
因此,适合这项工作的工具是 du
。但是为了 du
能够正确地完成他的工作而不是重复计算硬链接,您必须立即检查所有文件。幸运的是 du
的 GNU 版本有 --files0-from
选项,例如你可以使用
find . -type d ! -writable -print0 |
du -ch -d 1 --files0-from=- |
tail -n 1
这也避免了 xargs
由于 -I
选项可能会非常慢,这意味着您正在为每个参数执行 find
调用。
我不确定为什么你的命令给出了如此错误的数字,但这里有另一个你可以试试。
请注意,“它们占用的总大小” 可能与 ls
打印的大小总和有很大差异,这是由于文件系统块、硬链接等原因和稀疏文件。所以我们使用 du
而不是 ls
来获取尺寸。
下面的命令基本上是 ls
合并到同一搜索中并使用 -exec +
而不是 xargs -I
,这应该会大大加快命令速度,因为你 运行 第二个 find
只用了几次而不是每个目录一次。
#! /bin/bash
longlist() {
ls -l "$@" >> "$longlistfile"
}
filesonly() {
find "$@" -maxdepth 1 -type f -exec bash -c 'longlist "$@"' . {} + -print0
}
export -f longlist filesonly
export longlistfile=myfile.txt
rm -f "$longlistfile"
find . -type d \! -writable -exec bash -c 'filesonly "$@"' . {} + |
du -ch --files0-from=- | tail -n1