Linux【2】-管理文件-2-3-查看文件和文件夹大小(du)

du 命令,全称是 disk usage,用来展示磁盘使用量的统计信息。

du 和 df 算是一对同门师兄弟,du 侧重在文件夹和文件的磁盘占用方面,而 df 则侧重在文件系统级别的磁盘占用方面。这两个命令都非常的基础,也是每位 Linux 工程师都应该掌握的命令。

一、基本介绍

如果当前目录下文件和文件夹很多,使用不带参数du的命令,可以循环列出所有文件和文件夹所使用的空间。

这对查看究竟是那个地方过大是不利的,所以得指定 深入目录的层数,参数:–max-depth=,这是个极为有用的参数!如下,注意使用“*”,可以得到文件的使用空间大小.

[root@bsso yayu]# du -h --max-depth=1 work/testing  
27M     work/testing/logs  
35M     work/testing  
  
[root@bsso yayu]# du -h --max-depth=1 work/testing/* 
8.0K    work/testing/func.php  
27M     work/testing/logs  
8.1M    work/testing/nohup.out  
8.0K    work/testing/testing_c.php  
12K     work/testing/testing_func_reg.php  
8.0K    work/testing/testing_get.php  
8.0K    work/testing/testing_g.php  
8.0K    work/testing/var.php  
  
[root@bsso yayu]# du -h --max-depth=1 work/testing/logs/  
27M     work/testing/logs/  
  
[root@bsso yayu]# du -h --max-depth=1 work/testing/logs/*  
24K     work/testing/logs/errdate.log_show.log  
8.0K    work/testing/logs/pertime_show.log  
27M     work/testing/logs/show.log  

如果有一个进程在打开一个大文件的时候,这个大文件直接被rm 或者mv掉,则du会更新统计数值,df不会更新统计数值,还是认为空间没有释放。直到这个打开大文件的进程被Kill掉。

如此一来在定期删除 /var/spool/clientmqueue下面的文件时,如果没有杀掉其进程,那么空间一直没有释放。 使用下面的命令杀掉进程之后,系统恢复。

fuser -u /var/spool/clientmqueue

参数:

-a, --all
	显示对所有文件的统计,而不只是包含子目录。
-b, --bytes
	输出以字节为单位的大小,替代缺省时1024字节的计数单位。
--block-size=size
	输出以块为单位的大小,块的大小为 size 字节。( file- utils-4.0 的新选项)
-c, --total
	在处理完所有参数后给出所有这些参数的总计。这个选项被 用给出指定的一组文件或目录使用的空间的总和。
-D, --dereference-args
	引用命令行参数的符号连接。但不影响其他的符号连接。 这对找出象 /usr/tmp 这样的目录的磁盘使用量有用, /usr/tmp 等通常是符号连接。 译住:例如在 /var/tmp 下建立一个目录test, 而/usr/tmp 是指向 /var/tmp 的符号连接。du /usr/tmp 返回一项 /usr/tmp , 而 du - D /usr/tmp 返回两项 /usr/tmp,/usr/tmp/test。
--exclude=pattern
	在递归时,忽略与指定模式相匹配的文件或子目录。模式 可以是任何 Bourne shell 的文件 glob 模式。( file- utils-4.0 的新选项)
-h, --human-readable
	为每个数附加一个表示大小单位的字母,象用M表示二进制 的兆字节。
-H, --si
	与 -h 参数起同样的作用,只是使用法定的 SI 单位( 用 1000的幂而不是 1024 的幂,这样 M 代表的就是1000000 而不是 1048576)。(fileutils-4.0 的新选项)
-k, --kilobytes
	输出以1024字节为计数单位的大小。
-l, --count-links
	统计所有文件的大小,包括已经被统计过的(作为一个硬连接)。
-L, --dereference
	引用符号连接(不是显示连接点本身而是连接指向的文件或 目录所使用的磁盘空间)。
-m, --megabytes
	输出以兆字节的块为计数单位的大小(就是 1,048,576 字节)。
--max-depth=n
	只输出命令行参数的小于等于第 n 层的目录的总计。 --max-depth=0的作用同于-s选项。(fileutils-4.0的新选项)
-s, --summarize
	对每个参数只显示总和。
-S, --separate-dirs
	单独报告每一个目录的大小,不包括子目录的大小。
-x, --one-file-system
	忽略与被处理的参数不在同一个文件系统的目录。
-X file, --exclude-from=file
	除了从指定的文件中得到模式之外与 --exclude 一样。 模式以行的形式列出。如果指定的文件是'-',那么从标准输 入中读出模式。(fileutils-4.0 的新选项) GNU 标准选项
--help
	在标准输出上输出帮助信息后正常退出。
--version
	在标准输出上输出版本信息后正常退出。

二、具体用法说明

2.1 du 的最常用用法

最常用的用法,当然就是查看当前所在文件夹的总磁盘占用量了。

#列出当前目录下的文件和子文件夹
[roc@roclinux ruanjian]$ ls -F
curl-7.34.0.tar.gz  soft/  wordpress-4.4.1.tar.gz
 
#计算当前文件夹的总磁盘占用量, -s选项表示计算总和, -h选项表示以恰当的K/M/G单位展示
[roc@roclinux ruanjian]$ du -sh .
51M

这里有一个比较有意思的事情,在 Linux 命令中,-h选项常常代表“展示帮助信息”,即 –help 的缩写形式。但是,du 命令却不走寻常路,它的-h选项是 –human-readable 的缩写形式,表示以人类可读的形式展示磁盘使用量的单位名称(K/M/G)。

2.2 说说 -s 选项和 -c 选项的作用

-s选项,是 –summarize 的缩写形式,其作用是对 du 的每一个给定参数计算其磁盘使用量,我们来看例子。

#当前文件夹下有2个tar.gz文件和1个soft文件夹
[roc@roclinux ruanjian]$ ls -F
curl-7.34.0.tar.gz  soft/  wordpress-4.4.1.tar.gz
 
#通配形式的参数首先被Shell解析, 然后-s选项发挥作用, 展示每一个参数对应的磁盘空间使用量
[roc@roclinux ruanjian]$ du -sh *
3.4M    curl-7.34.0.tar.gz
41M     soft
6.8M    wordpress-4.4.1.tar.gz

而-c选项,是 –total 的缩写形式,它表示的是针对输出的各个对象来计算其磁盘使用量的总和。比如,我们想计算当前文件夹下所有后缀是 tar.gz 的文件的磁盘使用量总和,那么命令是这样的:

[roc@roclinux ruanjian]$ du -ch *.tar.gz
3.4M    curl-7.34.0.tar.gz
6.8M    wordpress-4.4.1.tar.gz
11M     总用量
可以看到,最后一行展示出的 11M,便是-c选项起到的求和作用。

当然,-c选项也可以计算文件和文件夹的混合求和:

[roc@roclinux ruanjian]$ du -ch curl-7.34.0.tar.gz soft
3.4M    curl-7.34.0.tar.gz
41M     soft
45M     总用量

在运维中,我们通常需要计算某一段时间范围内的日志文件的磁盘使用量,那么-c选项就可以很好地满足需求了。

2.3 用 –max-depth 选项控制深度

文件夹是可以嵌套的,有的时候,我们只想展示第一级或第二级子文件夹的信息,而不希望 du 统计的层次太深,那么我们可以用 –max-depth 选项来进行控制。

我们绘制了一个示意图,movies 文件中存储了中美两国 2016 年和 2017 年的一些电影大片,而且是按照类型来分的,包括探险片、爱情片、动作片。从图 1 中可以看出,movies 文件夹中共有 3 级子文件夹。

从图 1 中,我们可以很清晰地看到,当 –max-depth 是 0、1、2 时,du 分别对应哪一目录层级。

我们通过下面的例子,来实际看一下 –max-depth 的效果。

#我们模拟了和图8完全一致的目录结构

[roc@roclinux movies]$ tree
.
|-- China
|   |-- 2016
|   |   |-- Action
|   |   |   `-- yip_man.avi
|   |   |-- Adventure
|   |   |   `-- hero.avi
|   |   `-- Romance
|   |       `-- rose.avi
|   `-- 2017
|       |-- Action
|       |   `-- drunken_master.avi
|       |-- Adventure
|       |   `-- treatment.avi
|       `-- Romance
|           `-- banquet.avi
`-- USA
    |-- 2016
    |   |-- Action
    |   |   `-- gian.avi
    |   |-- Adventure
    |   |   `-- patton.avi
    |   `-- Romance
    |       `-- god_father.avi
    `-- 2017
        |-- Action
        |   `-- african_queen.avi
        |-- Adventure
        |   `-- star_wars.avi
        `-- Romance
            `-- citizen_kane.avi
 
 
#当--max-depth设定为0时, 只显示当前文件夹总大小
#可见, --max-depth=0的作用, 相当于-s
[roc@roclinux movies]$ du --max-depth=0 -h .
5.2G
 
#当--max-depth设定为1时, 则增加显示了第一级的文件夹大小
[roc@roclinux movies]$ du --max-depth=1 -h .
2.7G     ./China
2.5G     ./USA
5.2G     .
 
#当--max-depth设定为2时, 则会继续增加显示下一级子文件夹
[roc@roclinux movies]$ du --max-depth=2 -h .
1.4G     ./China/2017
1.3G     ./China/2016
2.7G     ./China
1.2G     ./USA/2017
1.3G     ./USA/2016
2.5G     ./USA
5.2G     .

以此类推,大家应该能够理解 –max-depth 的作用了吧。

2.4 -a 选项让 du 更博爱

默认情况下,du 命令只会关心文件夹,输出的都是文件夹的空间使用量,而不会关注单个文件。

如果想让 du 也关心单个的文件,有两种方法:

  1. 通过参数形式直接指定

  2. 通过-a选项让 du 输出包括文件夹和文件在内的完整统计信息

    #如果不指定-a选项 [roc@roclinux ruanjian]$ du -h . 41M ./soft 51M .

    #指定了-a选项之后, du则会刨根问底儿地把所有文件夹和文件都展示出来 [roc@roclinux ruanjian]$ du -ah . 6.8M ./wordpress-4.4.1.tar.gz 3.4M ./curl-7.34.0.tar.gz 980K ./soft/redis-2.6.16.tar.gz 40M ./soft/go1.1.2.Linux-amd64.tar.gz 41M ./soft 51M .

-a选项的威力还是很大的,即便是隐藏文件也会被囊括进来的,这时,有些用户的问题就随之而来了……

2.5 我想排除隐藏文件和隐藏文件夹,该怎么做

我猜就会有同学问这个问题的,所以,早就准备好了解决方案,是通过 du 的另一个重要参数 –exclude 来实现的。

#我们随意模拟了几个隐藏的文件和文件夹

[roc@roclinux ruanjian]$ du -ah .
6.8M    ./wordpress-4.4.1.tar.gz
3.4M    ./curl-7.34.0.tar.gz
980K    ./soft/redis-2.6.16.tar.gz
40M     ./soft/go1.1.2.Linux-amd64.tar.gz
120K    ./soft/.abc
0       ./.bbc/ddd
0       ./.bbc/.ccc
51M     .

#用–exclude的一个很简单的正则匹配, 就可以完美解决问题啦

[roc@roclinux ruanjian]$ du -ah --exclude="*/.*" .
6.8M    ./wordpress-4.4.1.tar.gz
3.4M    ./curl-7.34.0.tar.gz
980K    ./soft/redis-2.6.16.tar.gz
40M     ./soft/go1.1.2.Linux-amd64.tar.gz
41M     ./soft
51M     .

当然,学会了 –exclude 选项后,你完全可以根据自己的需求去过滤掉其他文件和文件夹了。

2.6 什么文件占满了我的磁盘

磁盘被占满,是 Linux 工程师经常遇到的问题,如果能够熟练使用 du 和 sort 形成组合拳,那么找到元凶并非难事。

#只想看当前文件夹下第一级的大小排序
[roc@roclinux ruanjian]$ du -sh *|sort -nr
41M     soft
6.8M    wordpress-4.4.1.tar.gz
3.4M    curl-7.34.0.tar.gz
 
#想看当前文件夹和其子文件夹下的大排序
[roc@roclinux ruanjian]$ du -ah .|sort -hr
51M     .
41M     ./soft
40M     ./soft/go1.1.2.Linux-amd64.tar.gz
6.8M    ./wordpress-4.4.1.tar.gz
3.4M    ./curl-7.34.0.tar.gz
980K    ./soft/redis-2.6.16.tar.gz

这里补充一个 sort 的知识点,那就是-h选项和-n选项的区别:

  • -n选项,按数值进行比较,只会傻傻地比较数字,它会认为 98 K大于 2G。
  • -h选项,会更加聪明,先优先比较单位(G>M>K),然后再对数值进行比较。

2.7 单位名称那些事

du 命令的单位名称有必要单独拿出来说说,这里面还是有不少坑的。

首先,要明确的是,du 的默认单位是 KB,也就是 1024bytes。我们来看一个例子。

#这里的单位就是KB, 按1KB=1024bytes计算, 是3530752bytes
[roc@roclinux ruanjian]$ du curl-7.34.0.tar.gz
3448    curl-7.34.0.tar.gz
 
#而这里可以很清楚地看到是MB
[roc@roclinux ruanjian]$ du -h curl-7.34.0.tar.gz
3.4M    curl-7.34.0.tar.gz

但 du 的单位,其实并没有这么简单,有不少只幕后黑手都可能会控制它,我们来一一曝光它们:

  1. 如果你通过 –block-size 选项设置了块大小,那么,这就会成为你 du 输出信息的单位。
  2. 假如上一条没满足,且你设置了环境变量 DU_BLOCK_SIZE,则这会成为你 du 输出信息的单位。
  3. 假如上两条都没满足,且你设置了环境变量 BLOCK_SIZE,则这会成为你 du 输出信息的单位。
  4. 假如前三条都没满足,且你设置了环境变量 BLOCKSIZE,则这会成为你 du 输出信息的单位。
  5. 假如前四条都没满足,且你开启了环境变量 POSIXLY_CORRECT,则 du 输出信息的单位会是 512 bytes。
  6. 假如前面的五条都没满足,那么 du 的输出信息的单位就是 1024 bytes,也就是 KB。

2.8 为什么 du 和 ls 输出的值不同

如果我告诉你说 du 和 ls 针对同一个文件,展示的大小是不一样的,你会不会很惊讶呢?

下面我们就用一个活生生的例子,先把这个“奇观”给大家展示出来。

#有一个文件, 里面只输入了a、b两个英文字母
[roc@roclinux ruanjian]$ cat myword
ab
 
#用下面的方法, 我们可以把文件中的控制字符也展示出来, 发现除了a、b外还包括了一个结尾符
[roc@roclinux ruanjian]$ sed -n l myword
ab$
 
#用ls来查看大小, 发现展示的是3字节
[roc@roclinux ruanjian]$ ls -l myword
-rw-rw-r-- 1 roc roc 3 2月  18 15:53 myword
 
#用du来查看大小, 竟然展示的是4KB字节
[roc@roclinux ruanjian]$ du myword
4       myword

du 命令的作者也太粗心了吧,竟然连字母个数都数不清么?冤枉啊!其实,du 和 ls 在展示文件大小时,是存在着本质区别的:

  • du 展示的是磁盘空间占用量。
  • ls 展示的是文件内容的大小。

可能这两句话还不足以让你理解两者的区别,我们举一个形象的例子。中秋节时,中国人走亲访友时都会购买月饼礼盒,月饼的体积可以认为是文件内容大小,而加上包装礼盒的总体积可以认为是磁盘空间使用量。

那么,在 Linux 的世界里,每个文件也要有包装么?要想解答这个问题,我们就要简单介绍下 Linux 文件系统的原理了。文件系统进驻磁盘之初,就会将磁盘按照固定数据块(block)大小进行分隔切块,通常情况下每一个固定数据块大小会被设定为 4096bytes,也就是 4KB。

与此同时,大部分文件系统规定:

  1. 一个数据块中最多存放一个文件的内容,当没存满时,剩余的空间不得被其他文件使用。
  2. 当一个文件的内容较大时,则可以存储到多个数据块中。

讲到这里,相信你应该有所领悟了,正是因为这样的管理规则,使得 du 和 ls 在大小展示上出现了差异。

我们再回过头来看一下刚才那个例子:

#有一个文件, 里面只输入了a、b两个英文字母
[roc@roclinux ruanjian]$ cat myword
ab
 
#用这个方法, 我们可以把文件里的控制字符也展示出来, 发现除了a、b外还包括了一个结尾符。
[roc@roclinux ruanjian]$ sed -n l myword
ab$
 
#用ls来查看大小, 发现展示的是3字节
[roc@roclinux ruanjian]$ ls -l myword
-rw-rw-r-- 1 roc roc 3 2月  18 15:53 myword
 
#用du来查看大小, 发现竟然展示的是4KB
[roc@roclinux ruanjian]$ du myword
4       myword

文件 myword 中只有三个字符,两个可见字符(ab)和一个控制字符($),因此,这个文件的内容大小就是 3bytes,但是限于 Linux 文件系统的限制,它需要占用一个数据块来存储这个文件,因此这个文件实际占用的磁盘空间就是 4KB 了。

这种情况使得 du 往往会比 ls 展示的文件大小要大一些。但是,还存在一种情况,那就是 du 展示的数值比 ls 展示的数值要小,这种现象,你知道原因么?

2.9 Linux 世界中也存在黑洞

说“黑洞”有些危言耸听,叫“空洞”或许更恰当些。“空洞”可以让一个文件的内容看起来很大,但其实磁盘占用却很小。这个表达,如果转换成 ls 和 du 命令的话,就是:“空洞”可以让一个文件的 ls 输出值很大,但 du 的输出值很小。

这是怎么做到的呢?让我们来亲手造一个“空洞”,一起见证奇迹(会用到 dd 命令):

#这是我们原有的那个文件
[roc@roclinux ruanjian]$ cat myword
ab
[roc@roclinux ruanjian]$ ls -l myword
-rw-rw-r-- 1 roc roc 3 2月  18 15:53 myword
 
#在myword文件中, 用dd神器来创造一个大小为1G的空洞
[roc@roclinux ruanjian]$ dd if=/dev/zero of=myword oflag=append bs=1M seek=1024 count=0
记录了0+0 的读入
记录了0+0 的写出
0字节(0 B)已复制, 1.44e-05 秒, 0.0 kB/秒
 
#我们看看myword文件内部发生了什么, 看到\000了么, 这就是空洞!
[roc@roclinux ruanjian]$ sed -n l myword
ab$
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
(此处省略数百行)
 
#用ls查看, myword已经变成1GB啦, 好大!
[roc@roclinux ruanjian]$ ls -hl myword
-rw-rw-r-- 1 roc roc 1.0G 2月  18 16:41 myword
 
#用du查看, myword现回原形, 还是那么小, 只增加了一个字节而已
[roc@roclinux ruanjian]$ du myword
4       myword

我们为大家展示了“du 的值远小于 ls 值的情况”,因为一个文件中的空洞,并不实际占用磁盘空间,但是这个空洞本身会被认为是文件内容的一部分,所以 ls 的值才会显示得那么大,而 du 的值还是会保持原大小。

多说一句,一个存在空洞的文件,官方术语叫作“稀疏文件”,英文叫作“sparse file”,它本质上是由文件偏移来控制的,如果对这

三、案例

3.1 常用的命令

查看系统中文件的使用情况

df -h

查看当前目录下各个文件及目录所占的空间大小

du -sh *

某个文件夹下指定2层以内的各个文件及文件夹大小

[root@bsso yayu]# du -h --max-depth=1 work/testing/logs/  

27M     work/testing/logs/
。。。。

【例 1】

[root@localhost ~]# du
#统计当前目录的总磁盘占用量大小,同时会统计当前目录下所有子目录的磁盘占用量大小,不统计子文件
#磁盘占用量的大小。默认单位为KB
20 ./.gnupg
#统计每个子目录的大小
24 ./yum.bak
8 ./dtest
28 ./sh
188
#统计当前目录总大小

【例 2】

[root@localhost ~]# du -a
#统计当前目录的总大小,同时会统计当前目录下所有子文件和子目录磁盘占用量的大小。默认单位为 KB

4 ./.bashjogout
36 ./install.log
4 ./.bash_profile
4 ./.cshrc
…省略部分输出…
188

【例 3】

[root@localhost ~]# du -sh
#只统计磁盘占用量总的大小,同时使用习惯单位显示
188K .

参考资料

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn