Как мне отсортировать вывод du -h по размеру

Мне нужно получить список читабельных выводов.

Тем не мение, 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 по размеру?

38 ответов

Решение

Начиная с версии GNU coreutils 7.5, выпущенной в августе 2009 года, 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)

du | sort -nr | cut -f2- | xargs du -hs

Существует очень полезный инструмент, который я использую под названием ncdu, который предназначен для поиска этих надоедливых папок и файлов с высоким уровнем использования диска и их удаления. Он консольный, быстрый и легкий, и имеет пакеты для всех основных дистрибутивов.

@ Дуглас Лидер, еще один ответ: Сортируйте удобочитаемый вывод 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`;die@h{sort%h}'
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh

Насколько я вижу, у вас есть три варианта:

  1. изменять du сортировать перед отображением.
  2. изменять sort поддерживать человеческие размеры для числовой сортировки.
  3. Выполните обработку вывода из сортировки, чтобы изменить базовый вывод на удобочитаемый.

Вы могли бы также сделать du -k и жить с размерами в КиБ.

Для варианта 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

У меня также была эта проблема, и я в настоящее время использую обходной путь:

du -scBM | sort -n

Это не приведет к получению масштабированных значений, но всегда даст размер в мегабайтах. Это менее чем идеально, но для меня это лучше, чем ничего (или отображение размера в байтах).

Нашел этот пост в другом месте. Таким образом, этот сценарий оболочки будет делать то, что вы хотите без вызова 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

(Я надеюсь, что 3,6M цветовых схем не является чрезмерным.)

Эта версия использует 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

Объяснение:

  • НАЧАЛО - создать строку для индексации, чтобы заменить 1, 2, 3 на K, M, G для группировки по единицам, если нет единицы (размер меньше 1 КБ), то совпадения нет, и возвращается ноль (отлично!)
  • напечатать новые поля - единицу измерения, значение (для правильной работы альфа-сортировки, с добавлением нуля, фиксированной длины) и исходную строку
  • индексировать последний символ поля размера
  • вытащить числовую часть размера
  • сортировать результаты, отбрасывать лишние столбцы

Попробуй без 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]]}'

Вот пример, который показывает каталоги в более краткой форме. Он обрабатывает пробелы в каталоге / именах файлов.

% 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

Сортировать файлы по размеру в мегабайтах

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

Есть еще один:

$ 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. Вероятно, часть ду тоже.

У меня есть простая, но полезная оболочка для Python du, которая называется dutop. Обратите внимание, что мы (сопровождающие coreutils) рассматриваем возможность добавления функциональности для сортировки для прямой сортировки "человеческого" вывода.

Этот фрагмент был бесстыдно заимствован из "Жан-Пьера" с http://www.unix.com/shell-programming-scripting/32555-du-h-sort.html. Есть ли способ, которым я могу лучше кредитовать его?

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;
     }
    '

Используйте флаг "-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

Нашел этот на линии... кажется, работает нормально

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

Вот простой метод, который я использую, очень низкое использование ресурсов и дает вам то, что вам нужно:

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

Другой:

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
  } <>'

Я узнал 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 с одним десятичным знаком.

Du -cka --max-глубина =1 /var/log | сортировать -rn | голова -10 | awk '{print ($1)/1024,"МБ", $2'}

Если вам нужно обрабатывать пробелы, вы можете использовать следующее

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

Дополнительный оператор sed поможет устранить проблемы с папками с такими именами, как поддержка приложений

Вот пример

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 или любое количество подпапок в указанном каталоге.

Другая 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

http://dev.yorhel.nl/ncdu

команда: ncdu

Навигация по каталогам, сортировка (имя и размер), графики, удобочитаемые и т. Д.

Я использовал решение, предоставленное @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);
}'

Вуаля:

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

Здесь много ответов, многие из которых являются дубликатами. Я вижу три тенденции: прохождение второго вызова du, использование сложного кода shell/awk и использование других языков.

Вот POSIX-совместимое решение с использованием du и awk, которое должно работать в любой системе.

Я выбрал немного другой подход, добавив -x чтобы убедиться, что мы остаемся в одной файловой системе (эта операция нужна мне только тогда, когда у меня мало места на диске, так зачем отсеивать то, что я смонтировал в этом дереве FS или переместил и символически связал назад?) и отображать постоянные единицы, чтобы сделать для облегчения визуального разбора. В этом случае я обычно выбираю не сортировать, чтобы лучше видеть иерархическую структуру.

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

(Так как это в последовательных единицах, вы можете добавить | sort -n если вы действительно хотите отсортировать результаты.)

Это отфильтровывает любой каталог, чье (совокупное) содержимое не может превышать 512 МБ, а затем отображает размеры в гигабайтах. По умолчанию du использует размер блока 512 байт (поэтому условие awk о 220 блоках составляет 512 МБ, а его делитель 221 преобразует единицы в ГБ - мы могли бы использовать du -kx с $1 > 512*1024 а также s/1024^2 быть более читабельным). В состоянии awk мы устанавливаем s к размеру, чтобы мы могли удалить его из строки ($0). Это сохраняет разделитель (который свернут в один пробел), поэтому окончательный %s представляет пробел, а затем имя агрегированного каталога. %7s выравнивает округлые %.2f Размер в ГБ (увеличить до %8s если у вас есть>10 ТБ).

В отличие от большинства решений здесь, это правильно поддерживает каталоги с пробелами в их именах (хотя каждое решение, включая это, будет неправильно обрабатывать имена каталогов, содержащие разрывы строк).

ду-с * | сортировать -nr | cut -f2 | xargs du -sh

Почему бы не бросить еще одну шляпу в кольцо... это старый вопрос, но вот пример, который (в основном) представляет собой чистый сценарий оболочки (fwiw) - то есть просто bash, а не perl/python/awk/etc. Так что в этом смысле, может быть, он предлагает что-то новое для обсуждения (или нет). Он рассчитывает размер файла только один раз, но печатает в различных единицах (мои предпочтения). (Неупрощенная версия включает в себя getopts, который исключает "ГБ", если это нежелательно.)

#!/bin/bash

printf -- ' %9s %9s %9s       %-30s\n' 'K'        'M'        'G'        'Path'
printf -- ' %9s %9s %9s       %-30s\n' '--------' '--------' '--------' '-----------'
du -sk "$@" | 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

Еще один du скрипт!

Поскольку уже есть много ответов, я просто публикую свой собственный сценарий там. Я использую с более чем восьми лет.

Это может быть запущено

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

где

  • необязательный флаг -b сказать, чтобы использовать количество байтов вместо количества блоков
  • необязательный путь в качестве 1-го аргумента, текущий каталог, если используется по умолчанию.
  • если второй аргумент не указан, минимальный размер для печати 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,

Вы можете показать их там или скачать там скрипт.

Другие вопросы по тегам