统计子目录大小情况并排序显示

本文介绍了一个Perl脚本,用于按大小降序排列指定目录下的文件及子目录,并可根据设定的最小大小过滤输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.chinaunix.net/u/6542/showart.php?id=394070

 

使用 du -sh * 可以显示指定目录下各文件/目录的大小情况,但是输出结果不够人性化(human-readable),以 /usr/share/目录为例

du -sh /usr/share/* 会输出如下信息

654K    /usr/share/aclocal
141K    /usr/share/aclocal-1.9
318K    /usr/share/alsa
145K    /usr/share/applications
1.9M    /usr/share/audacious
170K    /usr/share/audacious-plugins
24K /usr/share/aumix
1.2M    /usr/share/autoconf
926K    /usr/share/automake-1.9

如果要非常直观地按大到小显示个文件目录的大小,我们可以使用脚本来完成,对 du 后的信息进行处理后再按照要求输出,比如只输出大小在多少M以上的目录信息

这是很久以前的一个脚本,这几天正好有时间,就整理了下。

#!/usr/bin/perl

## filename: dfdir.pl
## script for getting file list of specified directory,
## then output them in order by size.

## Powered by Muddyboot, last modified: 2005-04-26
## only accept one parameter

$basename=substr($0,rindex($0,'/')+1);
sub usage() {
print "/nUsage: $basename DIRECTORY [MIN-SIZE]/n/n";
print "Get file list of DIRECTORY, then output them in order by size./n";
print "If MIN-SIZE is specified, only print those greater than MIN-SIZE./n";
print "MIN-SIZE is non-zero integer optionally followed by a k/K/m/M./n/n";
exit;
}

sub print_err () {
die "/n/e[1;31m$_[0]/e[0;39m/n/n";
}

die &usage if (@ARGV) < 1 ;
if ($ARGV[0] eq '-h' or $ARGV[0] eq '-help' or $ARGV[0] eq '--help') {
&usage;
}

## delete the last slash in dirname
($dir=$ARGV[0]) =~ s@/$@@;

## check if exists
&print_err("ERROR: destination: $dir does not exist.") if ! -e $dir;

## check if is a directory
&print_err("ERROR: destination: $dir is not an directory.") if ! -d $dir;

## get the filelist length and count the max length
opendir DH,"$dir" or die "/nCannot open directory: $dir/n/n";
$maxlen=0;

foreach $file (readdir DH) {
$curlen=length($file)+length($dir)+1;
if ($curlen > $maxlen) {
$maxlen=$curlen;
}
}
closedir DH;

## min size parameter control

if ($ARGV[1] ne "" ){
$msize=$ARGV[1];
if ($msize !~ /^[0-9]+$/ and $msize !~ /^[0-9]+[kKMm]$/ or $msize == 0 ) {
&usage;
} elsif ($msize =~ /[mM]$/) {
$msize =~ s/[mM]$//;
$msize *= 1024;
}
}

## get dir usage information
open INFO,"du -s $dir/*|sort -rn|" or &print_err("ERROR: Cannot open $dir.");

## process information and output
while (<INFO>) {
chomp;
my($size,$file)=/(/S+)/s+(.*)/;
if ($size > 1024*1024 and $size > $msize) {
printf "%5.1fG/t%s/n",$size/1024/1024,$file;
}
elsif ($size > 1024 and $size > $msize) {
printf "%5.1fM/t%s/n",$size/1024,$file;
}
elsif ($size > $msize) {
printf "%5dK/t%s/n",$size,$file;
} else {
last;
}
}


运行方式:dfdir.pl <目录名> [整数][k/m]

例子1:排序显示 /usr/share 下所有文件目录大小信息
dfdir.pl /usr/share

例子2:显示 /usr/share 下大于 5M 的文件或目录信息
dfdir.pl /usr/share 5m

输出结果如下:
113.6M  /usr/share/fonts
50.1M  /usr/share/man
32.5M  /usr/share/gtk-doc
18.9M  /usr/share/info
17.9M  /usr/share/themes
17.4M  /usr/share/vim
12.6M  /usr/share/xml
8.9M  /usr/share/icons

注:在裁减 debian 系统的时候,使用起来极其的方便

<think>我们正在使用`tree`命令,但需要注意的是,标准的`tree`命令本身不支持按文件大小排序。不过,我们可以结合其他命令(如`sort`)来实现类似功能。另外,`tree`命令有一个`-h`选项可以显示文件大小(人类可读格式),但它没有内置的排序选项来按大小排序。然而,我们可以通过以下步骤实现:1.使用`tree`命令生成带文件大小的列表(使用`-h`选项)。2.将输出通过管道传递给`sort`命令进行排序。但是,`tree`命令默认的输出格式是树状结构,包含目录和文件的层次关系,这种格式不适合直接使用`sort`排序(因为每行前面的缩进和符号会干扰排序)。因此,我们需要一种更结构化的输出。实际上,`tree`命令提供了一种“平面”输出模式(使用`-i`选项,即不显示树状结构,而是每行一个文件/目录),结合`-f`选项(显示完整路径)和`-h`选项(显示大小),我们可以得到每行一个条目,然后对大小进行排序。但是,由于`tree`命令显示大小是带单位的(如K、M、G),直接按字符串排序会导致数字和单位混合排序,这不是按数值大小排序。因此,我们需要将大小转换为统一的单位(例如KB),或者使用其他方法。另一种思路:不使用`tree`命令来排序,而是先用`find`命令列出所有文件,然后按大小排序,再用`tree`命令的类似格式显示?但这样比较复杂。考虑到用户要求使用`tree`命令,但`tree`本身不支持按大小排序,我们可以采取折中方案:方案1:使用`tree`生成带大小的列表,然后通过脚本处理排序(可能较复杂)。方案2:使用其他命令(如`find`)来获取文件列表大小排序,然后以类似树状的形式展示(但这不是真正的`tree`)。这里,我们介绍一个更简单的方法:使用`du`命令结合`sort`来按大小排序,然后如果需要树状结构,可以再考虑用其他方式。但是,用户明确要求使用`tree`命令。经过查阅,`tree`命令有一个`--du`选项(显示目录大小),但它主要用于显示目录的总大小,而不是每个文件的大小。而且,它也不支持按文件大小排序。因此,我们可能需要放弃使用`tree`来排序,而使用其他命令组合。但为了满足用户要求,我们可以尝试以下方法:使用`tree`的`-h`选项输出文件大小关闭树状结构(使用`-i`选项,即每行一个条目),然后使用`awk`或`sed`处理输出,提取大小和路径,再排序。具体步骤:1.使用`tree-hif`命令:-`-h`:打印人类可读的大小(带单位)-`-i`:不显示树状结构,每行一个条目-`-f`:打印每个文件或目录的完整路径(这样每行都是一个绝对路径或相对路径,取决于当前目录)但是,这样输出的每一行格式类似于:[大小]完整路径例如:1.0K./dir1/file1.txt2.然后,我们可以用`awk`提取大小和路径,大小转换为统一的数值(比如KB),然后排序。然而,由于大小单位不同(K、M、G),我们需要在`awk`中转换。这个处理相对复杂。另一种方法是使用`tree`的另一种输出格式:`tree-h-i-f--noreport`(`--noreport`不显示最后的统计信息)。然后,我们可以用`sort`的`-h`选项(支持人类可读大小排序,例如K、M、G)来排序。但是,`sort`的`-h`选项要求每行以数字开头(可能带单位),而`tree`的输出大小在行首,后面是路径,且大小和路径之间有空格。所以我们可以直接按第一列排序(但注意,目录行没有大小,所以需要过滤掉目录?或者使用`-d`选项只列出文件?)。但是,`tree`命令的输出中,目录行也有大小(如果使用`--du`则是目录总大小,但这里我们使用`-h`,每个文件或目录的大小是单独列出的)。如果我们只想排序文件,不包括目录,可以使用`-o`选项(但`tree`没有直接按文件过滤的选项)或者使用`-I`忽略目录?不,`tree`没有忽略目录的选项,但我们可以用`-d`只列出目录?这不是我们想要的。实际上,`tree`命令的`-f`选项输出的每一行,目录后面会有一个斜杠(/),我们可以利用这个来区分。但为了简化,我们可以先只考虑文件。我们可以这样:tree-hif--noreport|grep-v'/$'#排除目录(因为目录行以斜杠结尾)然后,使用`sort-h`(按人类可读的大小排序):tree-hif--noreport|grep-v'/$'|sort-h-r#按大小降序,-r表示反向(从大到小)但是,这样输出的顺序是按大小排的,但是每行的内容还是`tree`的输出格式(大小+完整路径)。注意:`sort-h`可以识别像'1K','2M','3G'这样的字符串正确排序。示例命令:tree-hif--noreport|grep-v'/$'|sort-h-r这样,我们就得到了按文件大小降序排列的文件列表(包括完整路径)。但是,这个命令有几个问题:-它排除了目录(因为去掉了以`/`结尾的行),但用户可能也想看到目录的大小?不过,用户要求的是“文件”,所以可以。-如果路径中包含空格,这个命令仍然可以工作,因为每行是一个完整的路径(由`-f`选项保证)。-但是,`tree`命令默认会递归所有子目录,所以符合要求。另外,如果系统没有`tree`命令,需要先安装(如`sudoaptinstalltree`)。总结步骤:1.安装`tree`(如果未安装):sudoaptinstalltree#Ubuntu/Debiansudoyuminstalltree#CentOS2.进入目标目录(或者指定目录),运行:tree-hif--noreport[目录路径]|grep-v'/$'|sort-h-r3.如果希望升序(从小到大),去掉`-r`:tree-hif--noreport[目录路径]|grep-v'/$'|sort-h注意:如果不指定目录路径,默认为当前目录。示例输出(降序):10M./largefile.mp45K./mediumfile.txt1K./smallfile.txt但是,这个输出丢失了`tree`的树状结构,因为`-i`选项已经去掉了树状结构。所以,我们实际上得到的是一个平面列表。如果用户希望保留树状结构,但按文件大小排序,那么目前的标准`tree`命令无法直接做到。因为树状结构是层次化的,而排序会打乱层次。因此,如果用户需要树状结构,则不能按文件大小排序。如果用户接受平面列表,则上述方法可行。另外,我们可以考虑使用`find`命令结合`du`和`sort`,然后通过类似`tree`的格式显示,但这需要自己编写脚本,比较复杂。所以,我们提供两种方案:方案A(平面列表,按大小排序):tree-hif--noreport[目录]|grep-v'/$'|sort-h-r方案B(使用其他工具模拟树状结构大小排序):这通常需要复杂的脚本,不推荐。因此,我们推荐方案A。另外,如果用户想包括目录的大小,那么可以去掉`grep-v'/$'`,但注意目录的大小在`tree-h`中显示的是目录本身的大小(通常很小,因为目录本身只是一个文件,记录其中文件的信息),而不是目录下所有文件的总大小。如果用户需要目录的总大小(递归计算),则应该使用`tree--du-h`,但这个输出格式又不同,且无法按每个条目排序(因为目录总大小是单独一行?)。所以,根据用户需求,我们专注于文件。命令总结:按文件大小降序(从大到小):tree-hif--noreport[目录]|grep-v'/$'|sort-h-r按文件大小升序(从小到大):tree-hif--noreport[目录]|grep-v'/$'|sort-h注意:`[目录]`是可选的,如果不写,就是当前目录。示例:tree-hif--noreport/home/user/documents|grep-v'/$'|sort-h-r另外,如果用户想要在排序后同时显示目录和文件(但目录按什么大小?目录本身的大小通常没有意义),那么可以尝试不排除目录,但排序时目录的大小(通常很小)会排在前面。命令如下:tree-hif--noreport[目录]|sort-h-r这样目录(以`/`结尾)也会被包括进来,大小排序(但注意目录的大小只是目录项的大小,不是递归大小)。因此,根据需求选择。由于用户要求的是“文件”,我们按文件处理。最后,如果用户希望输出树状结构,那么很遗憾,`tree`命令本身不支持按大小排序。我们可以考虑生成树状结构后,在每个文件前面加上大小,然后按大小排序,但这会破坏树状结构的层次。所以,如果必须要求树状结构,可能需要使用其他工具或者编写脚本。鉴于以上,我们提供平面列表的方案。另外,引用中提到的`tree`命令输出重定向到文件[^3]和`awk`提取字段[^4]也可以结合使用,比如:tree-hif--noreport|grep-v'/$'|sort-h-r|awk'{print$1,$2}'#但注意,如果路径有空格,$2可能不完整因为`tree`的输出格式是:大小(可能包含空格,比如'1.0K')和路径,但大小和路径之间是空格,而路径中也可能有空格。所以,我们不应该用空格分割,而是应该用第一个空格分割一次:用`awk`将第一个空格之前的部分作为大小,之后的部分作为路径。我们可以用:awk'{s=$1;$1="";prints,$0}'但这样会保留一个空格在路径前面,我们可以用`substr`去掉第一个空格,但更简单的是:tree-hif--noreport|grep-v'/$'|sort-h-r|awk'{size=$1;$1="";printsize,$0}'这样,第一列是大小,后面是完整的路径(包括可能存在的空格)。但是,这样输出会有一个空格在路径前面,我们可以用`sed`去掉开头的空格:...|awk'{size=$1;$1="";printsize$0}'#这样大小和路径之间没有空格,但路径前面有一个空格或者:...|awk'{size=$1;sub($1,"");printsize,$0}'注意:`sub($1,"")`会将第一个匹配$1(即大小字符串)的文本替换为空,但注意大小字符串可能包含正则元字符(如点),所以最好用`index`来定位。其实,我们也可以不处理,因为路径前面的空格不影响查看。所以,我们推荐直接使用之前的命令,不需要用`awk`处理,除非用户需要特定的格式。最终命令:降序:tree-hif--noreport[目录]|grep-v'/$'|sort-h-r升序:tree-hif--noreport[目录]|grep-v'/$'|sort-h注意:`--noreport`是为了去掉最后的总计行,以免干扰排序。如果用户想要在输出中包括目录,则去掉`grep-v'/$'`。另外,如果用户希望以树状结构显示排序后的结果,目前没有简单方法。但我们可以先按大小排序,然后对每个文件用`tree`单独显示?这也不现实。所以,我们提供平面列表的解决方案。引用说明:[^1]介绍了`tree`命令的基本信息。[^2]提到如果未安装`tree`,需要安装。[^3]提到可以将`tree`的输出重定向到文件,这里我们也可以重定向排序后的结果。[^4]提到`awk`可以用于文本处理,但在这个解决方案中我们没有必须使用`awk`,所以可选。因此,按照上述步骤操作即可。</think>在 Linux Shell 中使用 `tree` 命令按文件大小排序需要结合其他工具,因为 `tree` 本身不支持直接按大小排序。以下是两种实现方法: --- ### 方法 1:使用 `tree` + `sort`(推荐) #### 步骤: 1. **生成带大小的文件列表** 用 `tree -hif --noreport` 生成平面文件列表(无树状结构)显示大小: ```bash tree -hif --noreport /目标目录 ``` - `-h`:人类可读的大小(KB/MB/GB) - `-i`:取消树状缩进(每行一个文件) - `-f`:显示完整路径 - `--noreport`:不显示末尾统计信息 2. **过滤目录排序** 通过管道组合命令实现排序: ```bash tree -hif --noreport /目标目录 | grep -v '/$' | sort -h -r ``` - `grep -v '/$'`:排除目录行(目录以 `/` 结尾) - `sort -h -r`:按人类可读的大小降序排序(`-r` 表示从大到小) - 升序排序:去掉 `-r` 改为 `sort -h` #### 示例输出: ``` 12M ./videos/sample.mp4 2.5K ./docs/report.txt 1.2K ./scripts/backup.sh ``` --- ### 方法 2:使用 `find` + `sort`(更灵活) 若需要保留树状结构,先用 `find` 获取排序列表,再通过 `tree` 生成结构: ```bash # 1. 获取排序后的文件列表 find /目标目录 -type f -exec du -h {} + | sort -h -r # 2. 生成树状结构(独立操作) tree -h /目标目录 ``` --- ### 关键说明: 1. **目录与文件的区分** `tree` 输出中: - 目录以 `/` 结尾(如 `docs/`) - 文件无后缀(如 `report.txt`) 2. **排序原理** - `sort -h` 能识别人类可读大小(如 `10K` < `2M`) - 降序用 `-r`,升序直接 `sort -h` 3. **输出重定向** 结果保存到文件(参考引用[^3]): ```bash tree -hif --noreport /path | grep -v '/$' | sort -h -r > sorted_files.txt ``` --- ### 常见问题解决 - **未安装 `tree`**(参考引用[^2]): ```bash sudo apt install tree # Debian/Ubuntu sudo yum install tree # CentOS/RHEL ``` - **路径含空格的处理** 用 `awk` 调整输出格式(参考引用[^4]): ```bash tree -hif --noreport | grep -v '/$' | awk '{print $1,$2}' | sort -h -r ``` > 此方法适用于递归处理子目录,默认显示完整路径。如需限定目录深度,在 `tree` 后加 `-L N`(如 `-L 3` 限制3层)[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值