bash tricks: compararea a doua valori zecimale

Tema: sa se scrie un script bash care compara load average cu o valoare data. Se dau puncte suplimentare pentru portabilitate si flexibilitate.

Ha, intrebare de grupa mica! Simplu: preiei valoarea din /proc, cu cut -f2 -d\ /proc/loadavg si o compari cu valoarea citita din fisierul de configurare.
Aha. Cum compari 0.75 cu 1.5 ?

  • cu test nu merge, nu suporta decat operatii cu intregi;
  • cu arithmetic evaluation din bash iarasi nu merge, din acelasi motiv;
  • expr are aceeasi problema;
  • bc nu e neaparat disponibil out of the box;
  • un trick foarte perfid ar fi fost sa ma bazez pe faptul ca in /proc/loadavg apar exact 2 zecimale, asa ca puteam scoate punctul cu tr si aveam garantia ca am inmultit cu 100, asta ar fi insemnat un efort semnificativ de a garanta formatul in care apare valoarea data de utilizator, contrazicand principiul minimei surprize (diferente esentiale intre 2, 2.0, 2.00);
  • sa pornesc perl dintr-un script bash doar ca sa compar 2 numere e de-a dreptul hilar.

Cea mai decenta solutie gasita a fost cu awk: if [ $(echo $loadavg $test | awk '{if ($1>$2) print 1}') ] ; then ...

Sper sa mai fie de folos cuiva (sau macar sa aflu o solutie mai buna).

PS: wordpressul insista foarte tare sa schimbe apostroafele cu backtickuri sau alte chestii similare, asa ca grija mare la copy-paste!

5 Responses to “bash tricks: compararea a doua valori zecimale”

  1. Emil Sirbu Says:

    printf se incadreaza la portabilitate? Ca daca da, atunci un printf cu format (de ex.) %010.4 ar cam aduce 2, 2.0, 2.00 la aceasi forma 0002.0000

  2. petre Says:

    hmm, uite ca nu m-am gandit.

    if [ `printf '%010.4f' $loadavg| tr -d .` gt `printf '%010.4f' $test| tr -d .` ] ; then …

    Nice, dar cred in continuare ca e mai simplu cu awk :)

  3. zgrim Says:

    “sa pornesc perl dintr-un script bash doar ca sa compar 2 numere e de-a dreptul hilar.”

    Nah, hilar e ca tu te sperii de parca ar trebui sa pornesti Java.

    ]$ time perl -ane’$F[0]>shift&&print 1′ /proc/loadavg 0.01
    real 0m0.006s
    user 0m0.001s
    sys 0m0.004s

    ]$ time awk -v v=0.01 ‘{if ($1>v) print 1}’ /proc/loadavg
    real 0m0.005s
    user 0m0.000s
    sys 0m0.004s

  4. petre Says:

    Well, voiam sa zic ca mai bine rescriam tot scriptul in perl, nu ma asteptam sa ma lovesc de o problema atat de marunta si ca o forma sau alta de awk gasesti garantat pe orice masina linux.

    Si ca exista 3 awk-uri in Debian, tu pe care il ai? :P

  5. zgrim Says:

    “o forma sau alta de awk gasesti garantat pe orice masina linux.”
    Ofc, just like Perl.

    “Si ca exista 3 awk-uri in Debian, tu pe care il ai? :P
    GNU. Always GNU. Just GNU.

    ps: NU e flama perl vs awk, inutila de altfel (pt mine) – stii ce prefer – doar exprimarea cu “pornitu” perlului din bash a fost exagerata, dupa cum arata si cifrele. E ca si cum ai “porni” awk.
    pps: Nu tra sa rescrii totul in Perl (limbaj), dar poti folosi perl (program) si ca scula de sistem, inlocuitor sed/awk/cat/tail/sh/etc cu mare sugces. E una din puterile lui subversive la adresa Unix. :)