为什么 ls 与 awk 结合不显示确切的大小?

パンツ*_*パンツ 4 command-line files disk-usage ls awk

我试图以精确的字节数找到硬盘驱动器上文件的大小,但是每当大小变得太大时,数字就会变得很奇怪(例如 1.98329e+12)。我可以阻止它这样做或将其转换为精确的字节吗?

命令是:

ls -lR | grep -v '^d' | awk '{total += $5} END {print "Total:", total}'
Run Code Online (Sandbox Code Playgroud)

确切字节的图片:

图片

奇怪号码图片:

图片

  • 停止显示确切字节之前的截止点似乎在 500gb 左右
  • du -sb无论目录有多大,该命令都会正确显示确切的字节。
  • 我尝试过 Ubuntu Gnome 15.10 64bit(日语和英语)和 Linux Mint 17.3 Cinnamon 64bit(日语)
  • 我的驱动器是ntfs这样的,所以我尝试将其格式化为 ext4 并复制我的文件。结果与ntfs相同。

kos*_*kos 5

问题是 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
Run Code Online (Sandbox Code Playgroud)

您可以使用printf格式说明符而不是print*:

printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
Run Code Online (Sandbox Code Playgroud)
% printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
2147483648
Run Code Online (Sandbox Code Playgroud)

在你的情况下:

ls -lR | grep -v '^d' | awk '{total += $5} END {printf "Total:%.0f\n", total}'
Run Code Online (Sandbox Code Playgroud)
ls -lR |
    grep -v '^d' |
    awk '
        {
            total += $5
        }
        END {
            printf "Total:%.0f\n", total
        }
    '
Run Code Online (Sandbox Code Playgroud)

这将强制 AWK 以total十进制记数法而不是科学记数法打印。

但是,另一方面,您永远不应该解析ls.

一种更敏感的方法是使用find+ stat

find . -type f -exec stat -c '%s' {} + | awk '{total += $1} END {printf "Total:%.0f\n", total}'
Run Code Online (Sandbox Code Playgroud)
find . -type f -exec stat -c '%s' {} + |
    awk '
        {
            total += $1
        }
        END {
            printf "Total:%.0f\n", total
        }
    '
Run Code Online (Sandbox Code Playgroud)

*%.0f是一种使printf打印数字大于2147483647(2 31 -1)的技巧,当%d用作格式说明符时,它总是打印为2147483647. 的限制%.0f是在9007199254740992(2 53 )之后将开始失去精度,如果这是一个问题(感谢 Rotsor 提供有用的信息)。


Ser*_*nyy 5

TL;DRls并且awk对于您的目的来说是不必要的。在要分析的目录上使用du -cbdu -bs

你的目的是

  1. 查找所有文件
  2. 找到它们的大小(以字节为单位)
  3. 为所有人产生总计

所有这些操作都可以通过du.

$ du -bs $HOME 2>/dev/null                                                                 
76709521942 /home/xieerqi
Run Code Online (Sandbox Code Playgroud)

值得注意的是,它du有两种“模式”——它可以显示文件的大小或它占用的实际磁盘空间(真实的物理空间)。由于您对所有文件的总大小感兴趣,因此您需要明显的文件大小。-b标志准确地给出了(-b是 的别名--apparent-size --block-size=1)。

也许更简洁和适当的解决方案是du -bc直接在您想要的目录上使用。例如,我的主目录大小约为 76 GB

$ du -bc $HOME 2> /dev/null  | tail -1                    
76694582570 total
Run Code Online (Sandbox Code Playgroud)

出于某种原因,您担心文件夹大小和文件大小的差异。您在评论中说:

我更喜欢 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/
Run Code Online (Sandbox Code Playgroud)