我的目标相当简单:我想创建一个大目录中所有文件/目录的小型数据库。
在寻找合适的工具后,除了好的工具之外我找不到任何东西du
。我发现-b
如果我想要文件实际拥有的字节数并用于-a
列出所有文件,我应该使用。伟大的。
现在的问题是:我不想在du
的输出中包含目录。我希望每个文件都有这样的输出:size<tab>filename
这样我就可以将其转换为 CSV 或某种数据库。它包含目录的问题是,当我将其转换/导入到数据库后,我不知道如何将目录与文件分开,并且我不想最终意外地将文件作为目录,反之亦然。我也不想最终意外地计算出太多的总使用空间,因为当我汇总目录中的所有文件时,我已经得到了整个目录的大小,如果我在其上添加整个目录的大小,那就是太多了。
这就是为什么我不想使用find -type f
...(测试目录总共有38k个文件,真正的有数百万个)
$ time find -mindepth 1 -type f -exec du -sb {} > /dev/null \;
real 0m45.631s
user 0m25.807s
sys 0m18.946s
$ time du -ab > /dev/null
real 0m0.154s
user 0m0.057s
sys 0m0.096s
我愿意接受任何其他方式的建议来实现我的最初目标。我只需要一种方法来“浏览”目录并查看它们的大小(以及它们包含的文件的大小),而无需实际安装有问题的文件系统。 (有点像你可能会说的“离线”猴面包树)
答案1
请注意,du
报告文件的磁盘使用情况,而不是文件的大小(除非您使用--apparent-size
GNU 实现的选项du
(或-b
,另一个 GNU 扩展,它是 的缩写--apparent-size --block-size=1
))。
另请注意,
, 、 TAB 、换行符或"
与类 Unix 系统上文件名中的任何其他字符一样有效。
在这里,如果在 GNU 系统上,你可以这样做:
find . ! -type d -printf '%s,%P\0' |
LC_ALL=C sed -z 's/"/""/g; s/,/,"/; s/$/"/' |
tr '\0' '\n'
以 CSV 格式输出并报告除目录类型之外的所有文件的大小。
上面,我们告诉以 NUL 分隔的记录find
进行输出<size>,<filepath>
,因为 0 是唯一不能出现在文件名中的字节。我们在语言环境中使用sed
NUL 记录模式 ( -z
)来处理它C
(同样它可以处理任何字节值,即使是那些在用户语言环境中未形成有效字符的字节值),通过将 every 替换"
为""
(这是双引号通常转义的方式)在 CSV 中),并在记录中"
第一次出现 后添加一个( 后的那个),并在末尾添加一个 ( )。,
<size>
$
tr
将该输出上的 NUL 转换为 NL,因为 NL 是 CSV 中的记录分隔符。例如,调用的 15 字节文件$'a\nb"c'
将呈现为:
15,"a
b""c"
如果这确实是您想要的磁盘使用情况,您可以将其替换%s
为%b
以 512 字节为单位或%k
以千字节为单位的磁盘使用情况。
如果不是在 GNU 系统上(-printf
,-z
是 GNU 扩展),您可以使用perl
:
find . ! -type d -print0 |
perl -l -0ne '
if (@s = lstat$_) {
s/"/""/g; print qq($s[7],"$_")
} else {warn "$_: $!\n"}'
(-print0
也是一个 GNU 扩展,但现在,它出现在大多数其他find
实现中。如果没有,您可以使用它-exec printf '%s\0' {} +
)。
这次,如果您想要以 512 字节为单位的磁盘使用量,请替换7
为。12
无论如何,请注意目录(这是一种特殊类型的文件,包含文件名列表及其到 inode 的映射)本身也有大小。由实例报告的目录的累积磁盘使用量du -s some-dir
是该目录递归引用的所有唯一文件(任何类型,包括目录)的磁盘使用量之和,加上该目录本身的大小。
在这里,如果您想du
手动完成工作并能够报告相同的大小,您还需要记录目录文件的磁盘使用情况/大小,并记录文件何时重复(当有多个文件时)同一文件的名称,又名硬链接)。因此,除了大小/磁盘使用情况和文件路径之外,您还需要记录文件的设备和索引节点号 ( %D:%i
),这是文件的唯一标识符,因此du
能够判断两个文件路径何时引用相同的文件。
您可能还想记录文件的类型。和目录只有多种类型的文件中的一种。还有常规的文件,符号链接,先进先出,设备,插座... ( %y
)。