แยกวิเคราะห์ที่มีประโยชน์สำหรับตัวเลขที่มีคำต่อท้ายหน่วยหรือไม่


10

สมมติว่าคุณมีข้อมูลที่มีปริมาณในรูปแบบที่มนุษย์สามารถอ่านได้เช่นผลลัพธ์ของdu -hและต้องการใช้งานกับตัวเลขเหล่านั้นต่อไป สมมติว่าคุณต้องการไพพ์ข้อมูลของคุณผ่าน grep เพื่อทำการสรุปชุดย่อยของข้อมูลนั้น คุณทำสิ่งนี้ในหลาย ๆ ระบบที่คุณไม่เคยเห็นมาก่อนและมีเพียงยูทิลิตี้ขั้นต่ำเท่านั้น คุณต้องการแปลงคำต่อท้ายสำหรับส่วนต่อท้ายมาตรฐาน 10 ^ n ทั้งหมด

มียูทิลิตี gnu-linux ในการแปลงตัวเลขที่ต่อท้ายเป็นตัวเลขจริงภายในท่อหรือไม่? คุณมีฟังก์ชั่นทุบตีที่เขียนขึ้นเพื่อทำสิ่งนี้หรือบางส่วนของ perl ที่อาจจำได้ง่ายแทนที่จะเป็นความยาวของการเปลี่ยน regex หรือขั้นตอน 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

@djuarez: นั่นไม่เข้าท่าเลย คำตอบนี้เกี่ยวกับคำต่อท้าย SI ไม่ใช่หน่วยทั่วไป (วินาทีหรืออาจ?) เพื่อขยาย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.8th อันอื่นของไบต์?)

มิฉะนั้นคุณสามารถขอ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}'

สังเกตได้ดีว่ามีการสูญเสียความแม่นยำ การเสริมอินพุตให้กับหน่วยก็ใช้งานได้ แต่ฉันพบว่าunitsหายไปใน distro ขั้นต่ำของฉัน ฉันคิดว่าเราทุกคนทำสิ่งนี้แตกต่างกันถ้าเราควบคุมทุกอย่างได้อย่างเต็มที่
ถั่ว

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.