Почему не делает ls, объединенного с точными размерами шоу awk?

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

Команда:

ls -lR | grep -v '^d' | awk '{total += $5} END {print "Total:", total}'

Изображение точных байтов:

img

Изображение странного числа:

img

  • Предел, прежде чем это прекратит показывать точные байты, кажется, составляет приблизительно 500 ГБ
  • Команда du -sb правильно точные байты шоу, неважно, насколько большой каталог.
  • Я попробовал Ubuntu Gnome 15.10 64 бита (японский язык и английский язык) и Linux Mint 17.3 Корицы 64 бита (японский язык)
  • Мои диски ntfs таким образом, я пытался форматировать тот как ext4 и скопировать мои файлы. Результаты - то же как ntfs.
4
задан 7 April 2016 в 11:34

4 ответа

Проблема состоит в том, что MAWK (вариант AWK установил на Ubuntu) целыми числами печати по умолчанию, больше, чем 2147483647 (231-1) в экспоненциальном представлении:

% awk -W version
mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan

compiled limits:
max NF             32767
sprintf buffer      2040
% printf '2147483647\n' | awk '{x += $1; print x}'
2147483647
% printf '2147483648\n' | awk '{x += $1; print x}'
2.14748e+09

Вы могли использовать printf с форматом specifer вместо print*:

printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
% printf '2147483648\n' | awk '{x += $1; printf "%.0f\n", x}'
2147483648

В Вашем случае:

ls -lR | grep -v '^d' | awk '{total += $5} END {printf "Total:%.0f\n", total}'
ls -lR |
    grep -v '^d' |
    awk '
        {
            total += $5
        }
        END {
            printf "Total:%.0f\n", total
        }
    '

Это вынудит AWK распечатать total в десятичной записи вместо в экспоненциальном представлении.

Однако на другой ноте, Вы никогда не должны анализировать ls.

Более чувствительный способ сделать, который использовал бы find + stat:

find . -type f -exec stat -c '%s' {} + | awk '{total += $1} END {printf "Total:%.0f\n", total}'
find . -type f -exec stat -c '%s' {} + |
    awk '
        {
            total += $1
        }
        END {
            printf "Total:%.0f\n", total
        }
    '

*%.0f прием должен сделать printf числа печати, больше, чем 2147483647 (231-1), который при использовании %d поскольку спецификатор формата всегда печатал бы как 2147483647. Предел %.0f тот, начнет терять точность после 9007199254740992 (253), если это - когда-нибудь беспокойство (благодаря Rotsor для полезной информации).

5
ответ дан 23 November 2019 в 11:35

TL; DR: ls и awk являются ненужными для Вашей цели. Использовать du -cb или du -bs на каталоге, который Вы хотите проанализировать.

Ваша цель к

  1. Найдите все файлы
  2. найдите их размер (в байтах)
  3. произведите общий итог для всех них

Все эти действия могут быть выполнены du.

$ du -bs $HOME 2>/dev/null                                                                 
76709521942 /home/xieerqi

Стоит заметить это du имеет два "режима" - это может или показать, сколько файла находится в размере ИЛИ сколько пространства фактической дисковой емкости это поднимает (настоящий, физический агент по операциям с недвижимостью). Так как Вы интересуетесь общим размером всех файлов, Вы хотите очевидный размер файла. -b флаг дает точно это ( -b псевдоним для --apparent-size --block-size=1 ).

Возможно, еще более краткое и соответствующее решение состояло бы в том, чтобы использовать du -bc непосредственно на каталоге Вы хотите. Например, мой корневой каталог составляет приблизительно 76 ГБ в размере

$ du -bc $HOME 2> /dev/null  | tail -1                    
76694582570 total

По некоторым причинам Вы волнуетесь о разнице в размерах папки и размере файла. Вы сказали в комментариях:

Я предпочел бы ls, потому что размеры каталога варьируются, в то время как размеры файла являются постоянными

du является рекурсивным, и подводит итог размеров файла. Кроме того, каталог действительно имеет статический размер 4 096 байтов (4k), но с du это будет включено в результат du -bs directory_name . Рассмотрите это:

$ du -b suse/openSUSE-Leap-42.1-DVD-x86_64.iso                                             
4648337408  suse/openSUSE-Leap-42.1-DVD-x86_64.iso

$ du -b suse/                                                                              
4648341504  suse/

$ bc <<< "4648337408+4096" 
4648341504

$ mkdir suse/another_dir  

$ du -b suse/another_dir                                                                   
4096    suse/another_dir

$ du -bs suse/                                                                             
4648345600  suse/
5
ответ дан 23 November 2019 в 11:35

Под капотом, awk делает все вычисления с помощью чисел с плавающей точкой двойной точности. По умолчанию это печатает их использование printf(3) спецификатор формата %.6g, что означает, что, если число является больше чем шестью цифрами, широкими, оно переключится на электронную нотацию, которая является тем, что Вы видели. Можно работать вокруг этого путем установки переменной OFMT:

ls -lR |
    awk 'BEGIN { OFMT = "%d" }  
         /^-/  { total += $5 } 
         END   { print "Total:", total }'

Но существует верхний предел, вне которого это не может дать Вам точное число байтов; это начнет округлять младшие биты суммы. 500 гигабайтов = 500 * 1024 * 1024 * 1024 = 536870912000 &approx; 239. С обычной плавающей точкой IEEE это безопасно ниже того предела (который является примерно 252). Однако это является достаточно большим, что я лично чувствовал бы себя лучше с помощью языка программирования, который имел надлежащие "сверхбольшие числа" (целые числа неограниченного размера). Например, Python:

#! /usr/bin/python
import os
import sys

space = 0L  # L means "long" - not necessary in Python 3
for subdir, dirs, files in os.walk(sys.argv[1]):
    for f in files:
        space += os.lstat(os.path.join(subdir, f)).st_size

sys.stdout.write("Total: {:d}\n".format(space))

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

Это вычисляет число байтов, видимых в каждом файле, который совпадает со что ls -l печать. Если Вы хотите число байтов, на самом деле занял на диске вместо этого (что du печать), замена .st_size с .st_blocks * 512. (Да, множитель всегда 512, даже если st_blksize другое число.)

4
ответ дан 23 November 2019 в 11:35

Что Вы видите, вот способ отобразить большие количества. Например:

1.23e+3 = 1.23*10^3 = 1230

Насколько я знаю, Вы не можете выключить это, но как Вы записали в своем вопросе, du действительно ведет себя по-другому, таким образом, я рекомендовал бы использовать это. Иначе необходимо было бы преобразовать числа.

3
ответ дан 23 November 2019 в 11:35

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

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