Birim sonekleri olan numaralar için kullanışlı ayrıştırma?


10

Diyelim ki çıktı gibi insan tarafından okunabilir formatta miktarlara sahip verileriniz var du -hve bu sayılar üzerinde daha fazla işlem yapmak istiyorsunuz. Diyelim ki, bu verilerin bir alt kümesinin toplamını yapmak için verilerinizi grep aracılığıyla iletmek istiyorsunuz. Bu ad-hoc'u daha önce hiç görmediğiniz birçok sistemde yapıyorsunuz ve sadece asgari faydaları var. Tüm standart 10 ^ n sonekleri için sonek dönüşümleri istiyorsunuz.

Bir gnu-linux yardımcı programı, ekli sayıları bir boru hattı içinde gerçek sayılara dönüştürmek için var mı? Bunu yapmak için yazılmış bir bash fonksiyonunuz var mı yoksa regex replasmanlarının uzunluğu veya birkaç sed adımı yerine hatırlanması kolay bir perl var mı?

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


İlgili referanslar:


2
Nadiren grep ve awk kullanmanız gerekir. Awk kullanıyorsanız, awk kullanın. /200907/Satır başına kodunuzun önüne ekleyin , ör.awk '/200907/{s+=$1} END {print s}'
Tony

Yanıtlar:


14

Bağlantı verdiğiniz sorulardan birinde verdiğim yanıta dayanarak:

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

Kullanılan başka bir yöntem:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc

ikinci yöntem için, eğer sonek s ise?
djuarez

@djuarez: S hangi çarpanı temsil ediyor?
sonraki duyuruya kadar duraklatıldı.

Hiçbiri, sadece diğer birim durumlarda ekstrapolasyon.
djuarez

@djuarez: Bu hiç mantıklı değil. Bu cevap genel birimler değil, SI sonekleri ile ilgilidir (saniyeler, belki?). Cevabımdaki sedkomutu genişletmek için, komutta gösterdiğim gibi ek SI soneklerini işlemek için yan tümceler eklersiniz awk. s/T/ * 1000 G;başlangıçta örneğin terabayt eklenir.
sonraki duyuruya kadar duraklatıldı.

3

Bunu yapmak için perl düzenli ifadelerini kullanabilirsiniz. Örneğin,

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

Bu basit bir betik. Bunu başlangıç ​​noktası olarak düşünebilirsiniz. Umarım yardımcı olur!


Gerçekten de, bu bir yol. Ayrıca stackoverflow.com/questions/2557649/… da buldum .
fasulye

3

Şahsen, ilk başta -h bayrağını kullanmazdım. "İnsan tarafından okunabilir" sürüm, geri dönüştürüldüğünüzde tekrar yuvarlanması gereken sayıları yuvarlar ve daha az doğru olur. (Örneğin, 2.7MiB 2831155.2 bayttır. Diğer bir baytın 0.8'i ile ne yaptınız ??!)

Aksi takdirde, unitsMiB / GiB / KiB'yi sadece "B" ye dönüştürmeyi isteyebilirsiniz ve bununla başa çıkacaksınız, ancak (çıktınızın sekmeli olduğunu varsayarak, cutuygun şekilde)

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'

İyi not, hassasiyet kaybı var. Birimlere girdi eklemek de işe yarıyor .. ama unitsbenim en az dağıtımımda eksik buldum ! Sanırım her şey üzerinde tam kontrolümüz olsaydı hepimiz bunu farklı şekilde yapardık.
fasulye

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"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.