我正在尝试以精确的字节数找到硬盘上文件的大小,但每当文件大小过大时,数字就会变得很奇怪(例如 1.98329e+12)。我可以阻止它这样做吗,或者将其转换为精确的字节数?
命令是:
ls -lR | grep -v '^d' | awk '{total += $5} END {print "Total:", total}'
精确字节的图片:
奇怪数字的图片:
- 停止显示确切字节数的临界点似乎在 500gb 左右
du -sb
无论目录有多大,该命令都能正确显示精确的字节数。- 我尝试过 Ubuntu Gnome 15.10 64 位(日语和英语)和 Linux Mint 17.3 Cinnamon 64 位(日语)
- 我的驱动器是
ntfs
这样的,所以我尝试将其格式化为 ext4 并复制我的文件。结果与 ntfs 相同。
答案1
问题在于 MAWK(安装在 Ubuntu 上的 AWK 变体)默认以科学计数法打印大于2147483647
(2 31 -1) 的整数:
% awk -W version
mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan
compiled limits:
max NF 32767
sprintf buffer 2040
% printf '2147483647\n' | awk '{x += $1; print x}'
2147483647
% printf '2147483648\n' | awk '{x += $1; print x}'
2.14748e+09
您可以使用printf
格式说明符代替print
*:
printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
% printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
2147483648
就你的情况而言:
ls -lR | grep -v '^d' | awk '{total += $5} END {printf "Total:%.0f\n", total}'
ls -lR |
grep -v '^d' |
awk '
{
total += $5
}
END {
printf "Total:%.0f\n", total
}
'
total
这将强制 AWK以十进制表示法而不是科学计数法打印。
然而,另一方面,你永远不应该解析ls
。
更敏感的方法是使用find
+ stat
:
find . -type f -exec stat -c '%s' {} + | awk '{total += $1} END {printf "Total:%.0f\n", total}'
find . -type f -exec stat -c '%s' {} + |
awk '
{
total += $1
}
END {
printf "Total:%.0f\n", total
}
'
*是使打印数字大于(2 31 -1)%.0f
的技巧,当用作格式说明符时,将始终打印为。 的限制是,如果担心的话,在(2 53 )之后将开始失去精度(感谢 Rotsor 提供的有用信息)。printf
2147483647
%d
2147483647
%.0f
9007199254740992
答案2
总结:ls
和awk
对于您的目的来说不是必需的。在要分析的目录上使用du -cb
或。du -bs
你的目的是
- 查找所有文件
- 找到它们的大小(以字节为单位)
- 计算出所有这些的总数
所有这些操作都可以通过 来执行du
。
$ du -bs $HOME 2>/dev/null
76709521942 /home/xieerqi
值得注意的是,它du
有两种“模式”——它可以显示文件的大小或实际占用的磁盘空间(实际的物理空间)。由于您对所有文件的总大小感兴趣,因此您需要的是文件的实际大小。-b
flag 给出了确切的信息(-b
是 的别名--apparent-size --block-size=1
)。
也许更简洁、更合适的解决方案是du -bc
直接在你想要的目录上使用。例如,我的主目录大小约为 76 GB
$ du -bc $HOME 2> /dev/null | tail -1
76694582570 total
由于某种原因,您担心文件夹大小和文件大小的差异。您在评论中说:
我更喜欢 ls,因为目录大小会变化,而文件大小是恒定的
du
是递归的,并计算文件大小的总和。此外,目录确实具有 4096 字节 ( 4k ) 的静态大小,但du
它将包含在 的结果中du -bs directory_name
。考虑一下:
$ du -b suse/openSUSE-Leap-42.1-DVD-x86_64.iso
4648337408 suse/openSUSE-Leap-42.1-DVD-x86_64.iso
$ du -b suse/
4648341504 suse/
$ bc <<< "4648337408+4096"
4648341504
$ mkdir suse/another_dir
$ du -b suse/another_dir
4096 suse/another_dir
$ du -bs suse/
4648345600 suse/
答案3
在底层,awk
所有计算都使用双精度浮点数。默认情况下,它使用以下方式打印它们:printf(3)
格式说明符%.6g
,这意味着如果数字超过六位数字,它将切换到电子记法,这就是您所看到的。您可以通过设置变量来解决此问题OFMT
:
ls -lR |
awk 'BEGIN { OFMT = "%d" }
/^-/ { total += $5 }
END { print "Total:", total }'
但有一个上限,超过这个上限不能给出确切的字节数;它将开始对总和的低位进行四舍五入。500 GB = 500 * 1024 * 1024 * 1024 = 536870912000 ≈ 2 39。使用通常的 IEEE 浮点数,这安全地低于该限制(即大致2 52)。但是,这个数字已经足够大了,我个人觉得使用具有适当“大数”(无限制大小的整数)的编程语言会更好。例如,Python:
#! /usr/bin/python
import os
import sys
space = 0L # L means "long" - not necessary in Python 3
for subdir, dirs, files in os.walk(sys.argv[1]):
for f in files:
space += os.lstat(os.path.join(subdir, f)).st_size
sys.stdout.write("Total: {:d}\n".format(space))
这也完全不受文件名中含有不寻常字符的问题的影响。并且它计算隐藏文件占用的空间。
这将计算每个文件中可见的字节数,这与打印的内容相同ls -l
。如果您想要磁盘上实际占用的字节数而是(du
打印的内容),.st_size
用替换.st_blocks * 512
。(是的,乘数始终是 512,即使st_blksize
是不同的数字。)
答案4
您在此处看到的是一种显示大数字的方法。例如:
1.23e+3 = 1.23*10^3 = 1230
据我所知,您无法关闭此功能,但正如您在问题中所写,du
它确实表现不同,所以我建议使用此功能。否则,您必须转换数字。