Penguraian praktis untuk angka dengan akhiran unit?

10

Katakanlah Anda memiliki data dengan jumlah dalam format yang dapat dibaca manusia, seperti output dari du -h, dan ingin beroperasi lebih lanjut pada angka-angka itu. Katakanlah Anda ingin menyalurkan data Anda melalui grep untuk melakukan penjumlahan dari sub-set data tersebut. Anda melakukan ini ad-hoc pada banyak sistem yang belum pernah Anda lihat sebelumnya, dan hanya memiliki utilitas minimal. Anda ingin konversi sufiks untuk semua sufiks standar 10 ^ n.

Ada utilitas gnu-linux untuk mengubah angka sufiks menjadi bilangan real dalam pipa? Apakah Anda memiliki fungsi bash yang ditulis untuk melakukan ini, atau perl yang mungkin mudah diingat, alih-alih panjang penggantian regex atau beberapa langkah 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}'


Referensi yang relevan:

kacang polong
sumber
2
Anda jarang perlu menggunakan grep dan awk. Jika Anda menggunakan awk, maka gunakan awk. Cukup tambahkan /200907/di depan kode per-line Anda, mis.awk '/200907/{s+=$1} END {print s}'
Tony

Jawaban:

14

Berdasarkan jawaban saya di salah satu pertanyaan yang Anda tautkan:

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

Metode lain yang digunakan:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc
Dijeda sampai pemberitahuan lebih lanjut.
sumber
untuk metode kedua, bagaimana jika sufiksnya s?
djuarez
@djuarez: Pengganda apa yang digunakan untuk s?
Dijeda sampai pemberitahuan lebih lanjut.
Tidak ada, hanya ekstrapolasi pada case unit lainnya.
djuarez
@ Djuarez: Itu tidak masuk akal. Jawaban ini adalah tentang sufiks SI, bukan unit umum (detik, mungkin?). Untuk memperluas sedperintah dalam jawaban saya, Anda akan menambahkan klausa untuk menangani sufiks SI tambahan seperti yang saya tunjukkan dalam awkperintah. s/T/ * 1000 G;ditambahkan di awal akan menambah terabyte, misalnya.
Dijeda sampai pemberitahuan lebih lanjut.
3

Anda dapat menggunakan perl ekspresi reguler untuk melakukan ini. Sebagai contoh,

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

Ini adalah skrip sederhana. Anda bisa menganggapnya sebagai titik awal. Semoga ini bisa membantu!

Khaled
sumber
Memang ini satu arah. Saya juga menemukan stackoverflow.com/questions/2557649/… .
kacang
3

Secara pribadi, saya tidak menggunakan flag -h di tempat pertama. Versi "yang dapat dibaca manusia" membulatkan angka-angka yang perlu dibulatkan lagi ketika Anda mengonversi kembali, menjadi semakin tidak akurat. (Misalnya, 2.7MiB adalah 2831155.2 byte. Apa yang Anda lakukan dengan 0,8 byte lainnya ??!)

Jika tidak, Anda dapat meminta unitsuntuk mengonversi MiB / GiB / KiB menjadi hanya "B" dan itu akan menangani ini, tetapi Anda harus melakukan sesuatu seperti (dengan asumsi output Anda tab, jika tidak cuttepat)

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'
DerfK
sumber
Tercatat dengan baik, bahwa ada kehilangan presisi. Melengkapi input ke unit juga berfungsi .. tetapi saya menemukan unitshilang pada distro minimal saya! Saya pikir kita semua akan melakukan ini secara berbeda jika kita memiliki kendali penuh atas segalanya.
kacang
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
sumber