Как я могу сортировать 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 по размеру?

784 голоса | спросил Tom Feiner 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 16:42:42 +0300000000pmWed, 25 Feb 2009 16:42:42 +030009 2009, 16:42:42

30 ответов


1100

По состоянию на 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)

ответил ptman 1 J000000Thursday10 2010, 16:29:56
80
du | sort -nr | cut -f2- | xargs du -hs
ответил cadrian 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 16:52:03 +0300000000pmWed, 25 Feb 2009 16:52:03 +030009 2009, 16:52:03
56

@ Дуглас Ледер, еще один ответ: Сортируйте удобочитаемый результат с 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

EDIT: После нескольких раундов игры в гольф на PerlMonks окончательный результат следующее:

perl -e'%h=map{/.\s/;99**(ord$&&7)-$`,$_}`du -h`;[email protected]{sort%h}'
ответил Adam Bellaire 26 FebruaryEurope/MoscowbThu, 26 Feb 2009 00:04:55 +0300000000amThu, 26 Feb 2009 00:04:55 +030009 2009, 00:04:55
49

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

ответил 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 23:39:28 +0300000000pmWed, 25 Feb 2009 23:39:28 +030009 2009, 23:39:28
42
du -k * | sort -nr | cut -f2 | xargs -d '\n' du -sh
ответил 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 17:01:36 +0300000000pmWed, 25 Feb 2009 17:01:36 +030009 2009, 17:01:36
20

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

  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
ответил Douglas Leeder 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 16:53:52 +0300000000pmWed, 25 Feb 2009 16:53:52 +030009 2009, 16:53:52
19

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

du -scBM | sort -n

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

ответил Joachim Sauer 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 16:56:15 +0300000000pmWed, 25 Feb 2009 16:56:15 +030009 2009, 16:56:15
18

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

ответил Adam Bellaire 25 FebruaryEurope/MoscowbWed, 25 Feb 2009 17:09:00 +0300000000pmWed, 25 Feb 2009 17:09:00 +030009 2009, 17:09:00
14

В этой версии используется 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 - создать строку для индексации для замены 1, 2, 3 для K, M, G для группировки по единицам, если нет единицы (размер меньше 1K), тогда нет совпадения и возвращается нуль (отлично!)
  • напечатайте новые поля - unit, value (чтобы обработка альфа-сортировки работала правильно, она была заполнена нулями, фиксированная длина) и оригинальной линией
  • индекс последнего символа поля размера
  • вытащите цифровую часть размера
  • сортировать результаты, отбрасывать дополнительные столбцы

Попробуйте без команды 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]]}'
ответил Dennis Williamson 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 21:06:55 +0400 2009, 21:06:55
13

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

% 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
ответил Dennis Williamson 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 21:06:55 +0400 2009, 21:06:55
8

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

ответил pixelbeat 19 MaramThu, 19 Mar 2009 01:10:59 +03002009-03-19T01:10:59+03:0001 2009, 01:10:59
8

Получается другое:

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

ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
8

сортировать файлы по размеру в MB

du --block-size=MiB --max-depth=1 path | sort -n
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
6

Используйте флаг «-g»

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

И в моем /usr /локальном каталоге выводятся следующие данные:

$ 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
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
6

Этот фрагмент был бесстыдным зацепился от «Жан-Пьера» из 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;
     }
    '
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
4

Другой:

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
  } <>'
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
3

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

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
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
2

Я научился awk от придумывания этого примера вчера. Это заняло некоторое время, но было очень весело, и я научился использовать awk.

Он работает только один раз, и он имеет выход, очень похожий на 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 с одной десятичной точкой.

ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
2

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

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
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
2

du -cka --max-depth = 1 /var /log | sort -rn | head -10 | awk '{print ($ 1) /1024, "MB", $ 2'}

ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

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

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

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

ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

вуаля:

du -sk /var/log/* | sort -rn | awk '{print $2}' | xargs -ia du -hs "a"
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

http://dev.yorhel.nl/ncdu

Команда: ncdu

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

ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

Другое решение 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
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

Я использовал решение, предоставленное @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);
}'
ответил 0x89 4 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 04 Sep 2009 12:10:00 +0400 2009, 12:10:00
1

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

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

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

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

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

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

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

ответил Adam Katz 25 FebruaryEurope/MoscowbSat, 25 Feb 2017 03:31:17 +0300000000amSat, 25 Feb 2017 03:31:17 +030017 2017, 03:31:17
0

По крайней мере, с обычными инструментами это будет сложно из-за формата, в котором читаются человеческие числа (обратите внимание, что сортировка делает «хорошую работу» здесь, поскольку сортирует числа - 508, 64, 61, 2, 2 - он просто не может сортировать числа с плавающей запятой с дополнительным множителем).

Я бы попробовал это наоборот: используйте вывод «du | sort -n -r», а затем преобразуйте числа в удобочитаемый формат с помощью какого-либо скрипта или программы.

ответил Adam Katz 25 FebruaryEurope/MoscowbSat, 25 Feb 2017 03:31:17 +0300000000amSat, 25 Feb 2017 03:31:17 +030017 2017, 03:31:17
0

Что вы можете попробовать:

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

Надеюсь, что это поможет.

ответил Adam Katz 25 FebruaryEurope/MoscowbSat, 25 Feb 2017 03:31:17 +0300000000amSat, 25 Feb 2017 03:31:17 +030017 2017, 03:31:17
0
du | sort -nr | awk '{ cmd = "du -h -d0 "$2"| cut -f1"; cmd | getline human; close(cmd); print human"\t"$2 }'
ответил Adam Katz 25 FebruaryEurope/MoscowbSat, 25 Feb 2017 03:31:17 +0300000000amSat, 25 Feb 2017 03:31:17 +030017 2017, 03:31:17
0

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

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

Однако решение Кардриана более надежное, поскольку вышеприведенное не будет работать для очень густонаселенных деревьев, поскольку оно может превышать предел размера аргументов, переданных du

ответил Adam Katz 25 FebruaryEurope/MoscowbSat, 25 Feb 2017 03:31:17 +0300000000amSat, 25 Feb 2017 03:31:17 +030017 2017, 03:31:17

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132