it-swarm.cn

如何按大小对du -h输出进行排序

我需要获取人类可读的du输出列表。

但是,du没有“按大小排序”选项,并且对sort的管道传递不适用于人类可读的标志。

例如,运行:

du | sort -n -r 

输出按大小排序的磁盘使用量(降序):

du |sort -n -r
65108   .
61508   ./dir3
2056    ./dir4
1032    ./dir1
508     ./dir2

但是,使用人类可读的标志运行它时,排序不正确:

du -h | sort -n -r

508K    ./dir2
64M     .
61M     ./dir3
2.1M    ./dir4
1.1M    ./dir1

有人知道按大小对du -h进行排序的方法吗?

1029
Tom Feiner

从2009年8月发布的 GNU coreutils 7.5 开始,sort允许使用_-h_参数,该参数允许使用_du -h_产生的数字后缀:

_du -hs * | sort -h
_

如果您使用的是不支持_-h_的类型,则可以安装GNU Coreutils。例如,在较旧的Mac OS X上:

_brew install coreutils
du -hs * | gsort -h
_

sort手动

-h, --human-numeric-sort compare human readable numbers (e.g., 2K 1G)

1444
ptman
du | sort -nr | cut -f2- | xargs du -hs
89
cadrian

@Douglas Leeder,还有一个答案:使用另一种工具对du -h中人类可读的输出进行排序。像Perl!

du -h | Perl -e 'sub h{%h=(K=>10,M=>20,G=>30);($n,$u)=shift=~/([0-9.]+)(\D)/;
return $n*2**$h{$u}}print sort{h($b)<=>h($a)}<>;'

分成两行以适合显示。您可以以这种方式使用它,也可以将其制成单线,无论哪种方式都可以。

输出:

4.5M    .
3.7M    ./colors
372K    ./plugin
128K    ./autoload
100K    ./doc
100K    ./syntax

编辑:PerlMonks 打了几轮之后,最终结果如下:

Perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;[email protected]{sort%h}'
62
Adam Bellaire

我使用了一个非常有用的工具 ncd ,用于查找那些讨厌的高磁盘使用率文件夹和文件,并将其删除。它基于控制台,快速,轻便,并且在所有主要发行版中均提供了软件包。

57
neutral
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh
44
chrisharris.

据我所知,您有三个选择:

  1. 更改du在显示之前进行排序。
  2. 更改sort以支持用于数字排序的人员大小。
  3. 从排序中对输出进行后处理,以将基本输出更改为人类可读。

您也可以做du -k,并使用KiB中的尺寸。

对于选项3,您可以使用以下脚本:

#!/usr/bin/env python

import sys
import re

sizeRe = re.compile(r"^(\d+)(.*)$")

for line in sys.stdin.readlines():
    mo = sizeRe.match(line)
    if mo:
        size = int(mo.group(1))
        if size < 1024:
            size = str(size)+"K"
        Elif size < 1024 ** 2:
            size = str(size/1024)+"M"
        else:
            size = str(size/(1024 ** 2))+"G"

        print "%s%s"%(size,mo.group(2))
    else:
        print line
21
Douglas Leeder

我也遇到了这个问题,目前正在使用一种解决方法:

du -scBM | sort -n

这不会产生缩放的值,但始终会产生以兆字节为单位的大小。那还不算完美,但是对我而言总比没有好(或者以字节显示大小)。

20
Joachim Sauer

在其他地方找到 此发布 。因此,此Shell脚本将完成您想要的操作,而无需对所有内容调用du。它使用awk将原始字节转换为人类可读的格式。当然,格式略有不同(所有内容均以小数点后一位精度打印)。

#/bin/bash
du -B1 | sort -nr  |awk '{sum=$1;
hum[1024**3]="G";hum[1024**2]="M";hum[1024]="K";
for (x=1024**3; x>=1024; x/=1024){
        if (sum>=x) { printf "%.1f%s\t\t",sum/x,hum[x];print $2;break
}}}'

在我的.vim目录产生:

4.4M            .
3.6M            ./colors
372.0K          ./plugin
128.0K          ./autoload
100.0K          ./syntax
100.0K          ./doc

(我希望360万种配色不会过多。)

19
Adam Bellaire

此版本使用awk为排序键创建额外的列。它只调用一次du。输出应该看起来像du

我已将其拆分为多行,但可以将其重新组合为单行。

du -h |
  awk '{printf "%s %08.2f\t%s\n", 
    index("KMG", substr($1, length($1))),
    substr($1, 0, length($1)-1), $0}' |
  sort -r | cut -f2,3

说明:

  • BEGIN-创建一个索引字符串以用K,M,G替代1,2,3来按单位分组,如果没有单位(大小小于1K),则没有匹配项,并且返回零(完美! )
  • 打印新字段-单位,值(为使Alpha排序正常工作,将其填充为零,定长)和原始行
  • 索引大小字段的最后一个字符
  • 拉出尺寸的数字部分
  • 对结果进行排序,丢弃多余的列

不用cut命令尝试一下,看看它在做什么。

这是一个在AWK脚本中进行排序的版本,不需要cut

du -h |
   awk '{idx = sprintf("%s %08.2f %s", 
         index("KMG", substr($1, length($1))),
         substr($1, 0, length($1)-1), $0);
         lines[idx] = $0}
    END {c = asorti(lines, sorted);
         for (i = c; i >= 1; i--)
           print lines[sorted[i]]}'
15

这是一个以更紧凑的摘要形式显示目录的示例。它处理目录/文件名中的空格。

% du -s * | sort -rn | cut -f2- | xargs -d "\n" du -sh

53G  projects
21G  Desktop
7.2G VirtualBox VMs
3.7G db
3.3G SparkleShare
2.2G Dropbox
272M apps
47M  incoming
14M  bin
5.7M rpmbuild
68K  vimdir.tgz
15
slm

按大小(MB)对文件排序

du --block-size=MiB --max-depth=1 path | sort -n
12
lukmansh

我有一个简单但有用的python du的包装器 dutop 。直接输出。

9
pixelbeat

还有另一个:

$ du -B1 | sort -nr | Perl -MNumber::Bytes::Human=format_bytes -F'\t' -lane 'print format_bytes($F[0])."\t".$F[1]'

我开始喜欢Perl。您可能需要做一个

$ cpan Number::Bytes::Human

第一。对所有Perl黑客:是的,我知道排序部分也可以在Perl中完成。大概也是。

9
0x89

这个片段是从 http://www.unix.com/Shell-programming-scripting/32555-du-h-sort.html 的'Jean-Pierre'中无耻地sn取的。我有办法更好地相信他吗?

du -k | sort -nr | awk '
     BEGIN {
        split("KB,MB,GB,TB", Units, ",");
     }
     {
        u = 1;
        while ($1 >= 1024) {
           $1 = $1 / 1024;
           u += 1
        }
        $1 = sprintf("%.1f %s", $1, Units[u]);
        print $0;
     }
    '
8
Bozojoe

使用“ -g”标志

 -g, --general-numeric-sort
              compare according to general numerical value

并且在我的/ usr/local目录中产生如下输出:

$ du |sort -g

0   ./lib/site_Ruby/1.8/rubygems/digest
20  ./lib/site_Ruby/1.8/rubygems/ext
20  ./share/xml
24  ./lib/Perl
24  ./share/sgml
44  ./lib/site_Ruby/1.8/rubygems/package
44  ./share/mime
52  ./share/icons/hicolor
56  ./share/icons
112 ./share/Perl/5.10.0/YAML
132 ./lib/site_Ruby/1.8/rubygems/commands
132 ./share/man/man3
136 ./share/man
156 ./share/Perl/5.10.0
160 ./share/Perl
488 ./share
560 ./lib/site_Ruby/1.8/rubygems
604 ./lib/site_Ruby/1.8
608 ./lib/site_Ruby
7
Mick T

在网上找到了这个……似乎行得通

du -sh * | tee /tmp/duout.txt | grep G | sort -rn ; cat /tmp/duout.txt | grep M | sort -rn ; cat /tmp/duout.txt | grep K | sort -rn ; rm /tmp/duout.txt
5
Peter Nunn

这是我使用的简单方法,资源使用率非常低,可以满足您的需求:

du --max-depth=1 | sort -n | awk 'BEGIN {OFMT = "%.0f"} {print $1/1024,"MB", $2}'

0 MB ./etc
1 MB ./mail
2 MB ./tmp
123 MB ./public_html
4
JacobN

我昨天从构想这个例子中学到了awk。它花费了一些时间,但是却非常有趣,而且我学会了如何使用awk。

它只运行一次du,并且输出与du -h非常相似

du --max-depth=0 -k * | sort -nr | awk '{ if($1>=1024*1024) {size=$1/1024/1024; unit="G"} else if($1>=1024) {size=$1/1024; unit="M"} else {size=$1; unit="K"}; if(size<10) format="%.1f%s"; else format="%.0f%s"; res=sprintf(format,size,unit); printf "%-8s %s\n",res,$2 }'

它显示低于10的数字,带有一个小数点。

4
marlar

另一个:

du -h | Perl -e'
@l{ K, M, G } = ( 1 .. 3 );
print sort {
    ($aa) = $a =~ /(\w)\s+/;
    ($bb) = $b =~ /(\w)\s+/;
    $l{$aa} <=> $l{$bb} || $a <=> $b
  } <>'
4
Dimitre Radoulov

du -cka --max-depth = 1/var/log |排序-rn |头-10 | awk'{print($ 1)/ 1024,“ MB”,$ 2'}

3
Patrick

如果需要处理空格,可以使用以下命令

 du -d 1| sort -nr | cut -f2 | sed 's/ /\\ /g' | xargs du -sh

附加的sed语句将有助于减轻诸如Application Support之类名称的文件夹的问题

2
Chealion

Voilà:

du -sk /var/log/* | sort -rn | awk '{print $2}' | xargs -ia du -hs "a"
1
weeheavy

这里有很多答案,很多都是重复的。我看到了三种趋势:通过第二个du调用进行管道传输,使用复杂的Shell/awk代码以及使用其他语言。

这是一个使用 dawkPOSIX兼容解决方案,该解决方案适用于每个系统。

我采用了一种略有不同的方法,添加-x以确保我们保持在同一文件系统上(我只在磁盘空间不足时才需要执行此操作,所以为什么要清除掉我在其中安装的内容FS树还是向后移动并符号链接的?),并显示常量单位以简化视觉解析。在这种情况下,我通常选择not进行排序,这样我可以更好地进行排序请参阅层次结构。

Sudo du -x | awk '
  $1 > 2^20 { s=$1; $1=""; printf "%7sG%s\n", sprintf("%.2f",s/2^21), $0 }'

(由于这是一致的单位,因此,如果您确实要 sort ed结果,则可以附加| sort -n。)

这将筛选出(累积)内容超过512MB的所有目录,然后以GB为单位显示大小。默认情况下,du使用512字节的块大小(因此awk的条件为220 块是512MB,其221 除数会将单位转换为GB-我们可以将du -kx$1 > 512*1024s/1024^2结合使用,以便于人类阅读)。在awk条件内,我们将s设置为大小,以便可以从行($0)中将其删除。这将保留定界符(将其折叠到一个空格中),因此最后的%s代表一个空格,然后代表聚合目录的名称。 %7s对齐四舍五入的%.2f GB大小(如果大于10TB,则增加到%8s)。

与此处的大多数解决方案不同,这正确支持目录名称中带有空格的目录(尽管every解决方案,包括该解决方案,将错误处理包含换行符的目录名称)。

1
Adam Katz

另一个awk解决方案-

du -k ./* | sort -nr | 
awk '
{split("KB,MB,GB",size,",");}
{x = 1;while ($1 >= 1024) 
{$1 = $1 / 1024;x = x + 1} $1 = sprintf("%-4.2f%s", $1, size[x]); print $0;}'


[jaypal~/Desktop/Reference]$ du -k ./* | sort -nr | awk '{split("KB,MB,GB",size,",");}{x = 1;while ($1 >= 1024) {$1 = $1 / 1024;x = x + 1} $1 = sprintf("%-4.2f%s", $1, size[x]); print $0;}'
15.92MB ./Personal
13.82MB ./Personal/Docs
2.35MB ./Work Docs
1.59MB ./Work Docs/Work
1.46MB ./Personal/Raa
584.00KB ./scan 1.pdf
544.00KB ./Personal/Resume
44.00KB ./Membership.xlsx
16.00KB ./Membership Transmittal Template.xlsx
1
user96753

http://dev.yorhel.nl/ncd

命令:ncdu

目录导航,排序(名称和大小),图形,可读性等。

1
Adam Eickhoff

我一直在使用@ptman提供的解决方案,但是最近的服务器更改使其不再可行。相反,我使用以下bash脚本:

#!/bin/bash
# File: duf.sh
# list contents of the current directory by increasing 
#+size in human readable format

# for some, "-d 1" will be "--maxdepth=1"
du -k -d 1 | sort -g | awk '
{
if($1<1024)
    printf("%.0f KB\t%s",$1,$2);
else if($1<1024*1024)
    printf("%.1f MB\t%s",$1/1024,$2);
else
    printf("%.1f GB\t%s",$1/1024/1024,$2);
}'
1
Keith Yoder

du -s * |排序-nr |切-f2 | xargs du -sh

1
ageek2remember

这是一个例子

du -h /folder/subfolder --max-depth=1 | sort -hr

返回值:

233M    /folder/subfolder
190M    /folder/subfolder/myfolder1
15M     /folder/subfolder/myfolder4
6.4M    /folder/subfolder/myfolder5
4.2M    /folder/subfolder/myfolder3
3.8M    /folder/subfolder/myfolder2

您也可以添加| head -10查找指定目录中的前10个或任意数量的子文件夹。

1
ode2k

这是我的.profile中的别名

别名du ='Sudo du -xh --max-depth = 1 |排序-h'

sort -h是真正帮助解决所问问题的方法。

另一个有用的选项是du -x以保留在同一文件系统上。如果有些目录不是世界可读的,那么Sudo还可以帮助避免看到错误。此外,我总是做---max-depth = 1,然后进一步向下钻取等。

0
Tagar

还有另一个du脚本!

因为已经有了很多答案,所以我只在此处发布自己的脚本。我使用超过八年了。

这可以通过运行

/somepath/rdu.sh [-b] [/somepath] [minSize]

哪里

  • 可选标志-b告诉使用字节数而不是块数
  • 可选path作为第一个参数,默认为当前目录。
  • 如果未提供第二个参数,则要打印的最小尺寸为256Mb

输出看起来像:

\___   3.01G                 21.67%                .cache
|   \___   1.37G                 45.54%                mozilla
|   |   \___   1.37G                100.00%                firefox
|   |   |   \___ 581.71M                 41.48%                billiethek.default
|   |   |   |   \___ 522.64M                 89.85%                cache2
|   |   |   |   |   \___ 522.45M                 99.96%                entries
...

有脚本:

#!/bin/bash

if [ "$1" == "-b" ] ;then
    shift
    units=(b K M G T P)
    duargs="-xbs"
    minsize=${2:-$((256*1024**2))}
else
    units=(K M G T P)
    duargs="-xks"
    minsize=${2:-$((256*1024))}
fi

humansize() {
    local _c=$1 _i=0
    while [ ${#_c} -gt 3 ] ;do
        ((_i++))
        _c=$((_c>>10))
    done
    _c=$(( ( $1*1000 ) >> ( 10*_i ) ))
    printf ${2+-v} $2 "%.2f%s" ${_c:0:${#_c}-3}.${_c:${#_c}-3} ${units[_i]}
}
percent() {
    local p=000$((${1}00000/$2))
    printf ${3+-v} $3 "%.2f%%" ${p:0:${#p}-3}.${p:${#p}-3}
}

device=$(stat -c %d "${1:-.}")
printf -v sep "%16s" ""

rdu() {
    local _dir="$1" _spc="$2" _crt _siz _str _tot _pct
    while read _siz _crt;do
        if [ "$_crt" = "total"  ]; then
            _tot=$_siz
        else
            [ "$_tot" ] || _tot=$_siz
            if [ $_siz -gt $minsize ];then
                humansize $_siz _str
                percent $_siz $_tot _pct
                printf "%s\___ %7s%s%7s%s%s\n" \
                    "$_spc" $_str "$sep" $_pct "$sep" "${_crt##*/}"
                [ -d "$_crt" ] &&
                [ $(stat -c %d "$_crt") -eq $device ] &&
                rdu "$_crt" "|   $_spc"
            fi
        fi
    done < <(
        find "$_dir" -mindepth 1 -maxdepth 1 -xdev \
            \( -type f -o -type d \) -printf "%D;%p\n" |
            sed -ne "s/^${device};//p" |
            tr \\n \\0 |
            xargs -0 du ${duargs}c |
            sort -nr
    )
}

rdu "${1:-.}"

不,我不会将它们发布在Git***.xxx

您可以 在此处显示它们在此处下载脚本。

0
F. Hauri

这是我的解决方案,一个简单的bash脚本,仅调用du一次,并且仅显示大小为1 MB或更大的目录:

#!/bin/env bash
# Usage: my_du.sh [subdirectory levels]
#   For efficiency, only calls "du" once, and stores results in a temp file
#   Stephen Becker, 2/23/2010

if [ $# -gt 0 ]; then
# You may prefer, as I do, to just summarize the contents of a directory
# and not view the size of its subdirectories, so use this:
    du -h --max-depth $1 > temp_du_file
else
    du -h > temp_du_file
fi


# Show all directories of size > 1 GB:
cat temp_du_file | grep "^\([0-9]\|\.\)\+G" | sort -nr
# Show all directories of size > 1 MB:
cat temp_du_file | grep "^\([0-9]\|\.\)\+M" | sort -nr

rm temp_du_file
0
Stephen

至少对于普通工具而言,这将是困难的,因为人类可读的数字所采用的格式(请注意,sort在对数字进行排序时做得很好,因为它对数字进行排序-508、64、61、2、2-只是无法使用额外的乘数对浮点数进行排序)。

我会尝试另一种方式-使用“ du | sort -n -r”的输出,然后使用一些脚本或程序将数字转换为人类可读的格式。

0
schnaader

您可以尝试的是:

for i in `du -s * | sort -n | cut -f2`
do
  du -h $i;
done

希望能有所帮助。

0
Christian Witts
du | sort -nr | awk '{ cmd = "du -h -d0 "$2"| cut -f1"; cmd | getline human; close(cmd); print human"\t"$2 }'
0
Nathan de Vries

以下解决方案与cadrian的原始解决方案类似,但是此操作仅运行2 du命令,而不是树中每个目录一个du。

du -hs `du |sort -g |cut -f2- `

但是Cardrian的解决方案更强大,因为上面的方法不适用于人口稠密的树木,因为它可能超出传递给du的参数大小的限制

0
Steve Weet

松散地基于 此单线 中的逻辑,我编写了一个脚本,该脚本提供了可人类读取的排序输出。除了要求-h标志以提高可读性,不需要其他非POSIX兼容命令。

它在 https://github.com/pleappleappleap/sorted-human-d 处可用。

0
Tripp Kinetics

为什么不给它戴上帽子呢……这是一个老问题,但这是一个(主要)纯Shell脚本(fwiw)的示例-即,仅bash而没有Perl/python/awk/etc。因此从某种意义上说,它可能为讨论提供了新的东西(或没有)。它仅计算一次文件大小,但以各种单位打印(我的偏好)。 (未经简化的版本包括getopts,如果不需要的话,它会排除“ GB”。)

#!/bin/bash

printf -- ' %9s %9s %9s       %-30s\n' 'K'        'M'        'G'        'Path'
printf -- ' %9s %9s %9s       %-30s\n' '--------' '--------' '--------' '-----------'
du -sk "[email protected]" | while read val; do
    file=$(echo "$val" | cut -f2-)
    size_k=$(echo "$val"  | cut -f1)
    printf ' %9s %9s %9s       %-30s\n' \
          ${size_k}  \
          $(( size_k / 1024 ))  \
          $(( size_k / 1024 / 1024 ))  \
          "$file"
  done | sort -n
0
michael

降序排列。

du -s ./* | sort -n| cut -f 2-| xargs du -sh {}
0
Peter Nduati