Удобный анализ чисел с единичными суффиксами?

10

Допустим, у вас есть данные с количествами в удобочитаемом формате, например, вывод du -h, и вы хотите в дальнейшем работать с этими числами. Допустим, вы хотите передать данные через grep для суммирования подмножества этих данных. Вы делаете это ad-hoc на многих системах, которые вы никогда раньше не видели, и используете только минимальные утилиты. Вам нужны преобразования суффиксов для всех стандартных суффиксов 10 ^ n.

Существует ли утилита gnu-linux для преобразования суффиксных чисел в реальные числа в конвейере? У вас есть функция bash, написанная для этого, или какой-нибудь Perl, который может быть легко запомнить, вместо длины регулярных выражений или нескольких шагов sed?

38M     /var/crazyface/courses/200909-90147
2.7M    /var/crazyface/courses/200909-90157
1.1M    /var/crazyface/courses/200909-90159
385M    /var/crazyface/courses/200909-90161
1.3M    /var/crazyface/courses/200909-90169
376M    /var/crazyface/courses/200907-90171
8.0K    /var/crazyface/courses/200907-90173
668K    /var/crazyface/courses/200907-90175
564M    /var/crazyface/courses/200907-90178
4.0K    /var/crazyface/courses/200907-90179

| grep 200907 | <amazing suffix conversion> | awk '{s+=$1} END {print s}'


Соответствующие ссылки:

фасоль
источник
2
Вам редко нужно использовать grep и awk. Если вы используете awk, используйте awk. Просто добавьте /200907/перед вашим кодом для каждой строки, например,awk '/200907/{s+=$1} END {print s}'
Тони

Ответы:

14

На основании моего ответа на один из вопросов, на которые вы ссылаетесь:

awk '{
    ex = index("KMGTPEZY", substr($1, length($1)))
    val = substr($1, 0, length($1) - 1)

    prod = val * 10^(ex * 3)

    sum += prod
}
END {print sum}'

Другой метод, который используется:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc
Приостановлено до дальнейшего уведомления.
источник
для второго метода, что если суффикс s?
djuarez
@djuarez: Какой множитель обозначает s?
Приостановлено до дальнейшего уведомления.
Нет, просто экстраполирую на другие случаи блока.
djuarez
@djuarez: Это не имеет никакого смысла. Этот ответ о суффиксах СИ, а не общих единицах (секунды, возможно?). Чтобы расширить sedкоманду в моем ответе, вы добавили бы предложения для обработки дополнительных суффиксов SI, как я показываю в awkкоманде. s/T/ * 1000 G;добавленный в начале добавил бы терабайт, например.
Приостановлено до дальнейшего уведомления.
3

Вы можете использовать регулярные выражения Perl, чтобы сделать это. Например,

$value = 0;
if($line =~ /(\d+\.?\d*)(\D+)\s+/) {
   $amplifier = 1024 if ($2 eq 'K');
   $amplifier = 1024 * 1024 if ($2 eq 'M');
   $amplifier = 1024 * 1024 * 1024 if ($2 eq 'G');
   $value = $1 * $amplifier;
}

Это простой скрипт. Вы можете рассматривать это как отправную точку. Надеюсь, это поможет!

Халед
источник
Действительно, это один из способов. Я также нашел stackoverflow.com/questions/2557649/… .
бобы
3

Лично я бы просто не использовал флаг -h. «Человекочитаемая» версия округляет числа, которые нужно будет снова округлить при обратном преобразовании, получая еще менее точные значения. (Например, 2.7MiB - 2831155.2 байта. Что вы делали с остальными 0.8-м байтом ??!)

В противном случае, вы можете попросить unitsпреобразовать MiB / GiB / KiB просто в «B», и он справится с этим, но вам придется сделать что-то вроде (при условии, что ваш вывод вкладок, в противном случае cutсоответственно)

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'
DerfK
источник
Хорошо отмечено, что есть потеря точности. Дополнение ввода к единицам также работает .. но я обнаружил, что unitsотсутствует в моем минимальном дистрибутиве! Я думаю, что мы все сделали бы это по-другому, если бы у нас был полный контроль над всем.
бобы
2
VALUE=$1

for i in "g G m M k K"; do
        VALUE=${VALUE//[gG]/*1024m}
        VALUE=${VALUE//[mM]/*1024k}
        VALUE=${VALUE//[kK]/*1024}
done

[ ${VALUE//\*/} -gt 0 ] && echo VALUE=$((VALUE)) || echo "ERROR: size invalid, pls enter correct size"
S471
источник