bash osztás

Halihóóó Emberek!

Egész számot, amely byte - okat jelent, szeretnék 1024 - el osztani, hogy G, M vagy kbyte - okat kapjak. Az eredmény két tizedesjegyig kellene. Külső program (pl. bc) vagy más nyelven írt script beágyazása nélkül megoldható - e ez tisztán bash módszerrel?

Hozzászólások

Nem lehetséges, amennyire tudom.
Ha shell-csere megoldható, akkor javaslom a zsh-t (ld. itt, "Floating Point Math" rész).

Ahogy Zahy is írta. Lényegében hogy oly módon lehet megoldani ("kerülő" úton), hogy a százszorosával végzem a műveleteket, utána pedig maradékos osztással megkapom a kívánt eredményt. Erre gondoltam, hogy ez nem jutott eszembe, pedig már én is használtam párszor (nem bash-nál).

Esetleg, bar ez azert nem teljesen igaz, kiindulasnak jo lehet.
x=2;y=3;r=$((x/y)).$((100*x/y)); echo $r

Ez már sokkal jobb, de nem elég pontos:

calc 23456789/1024
	22907.0205078125
x=23456789;y=1024;r="$((x/y)).$((100*(x%y)/y))";echo $r
22907.2

Nekem is van egy megoldásom, modulo használata nélkül, de sajnos az is pont ugyanígy hibázik.

x=23456789;y=1024;r=$((x/y)).$((100*x/y-(x/y)*100)); echo $r
22907.2

Tipp: ha csak egy tizedesig számolunk így, akkor pontosabb az eredmény.

-----

(&%;_98\<|{3W10Tut,P0/on&Jkj"Fg}|B/!~}|{z(8qv55sr1C/n--k**;gfe$$5a!BB]\.-

printf "%.2f\n", $(($bytes*100/1024))

Ez így nem jó?

Mi is az, hogy "tisztán bash"?
A bash-nak lényegi része, hogy bc-t, vagy awk-t vagy cut-ot ... stb hívogatunk. A grep-ről nem is beszélve. Az sem része a bash-nak.

Ha elmondod mi a feladat, lehet hogy más utat is találunk, és nem kell számoltatni.
Pl: ha file méreteket akarsz megjeleníteni, akkor az ls -h ugyanígy mutatja, illetve a du -sh is. Csak példa volt, de lehet máshol is van ilyen megoldás. Ne számolj ha nem muszáj. ;)

---
"A megoldásra kell koncentrálni nem a problémára."

A bash-nek nem része egyik említett program sem.
Valamennyi használata plusz processz indítást jelent, aminek elég nagy az erőforrásigénye.

De én továbbra is (immár kipróbáltan) kitartok amellett, hogy az osztandót fel kell szorozni 100-zal, elvégezni az osztást, észben tartani, hogy az eredménye épp százszorosa a ténylegesnek és amikor ki kell írni, akkor printf, formátumként "%.2f", értékként meg $(($eredmeny/100)) és probléma letudva.
(kerekítés nem erőssége, de itt asszem, nincs jelentősége)

nálam:
bytes=100;printf "%.2f\n" $(($bytes*100/1024))
9,00
ugyhogy valami gond van ezzel. (a vesszo szerintem nem kell) -- nem tudtam hogy printf is van a bash-ban. mindenesetre ha mar van akkor en is eloallok egy lehetoseggel (ez egy szkript vagy mi)
x=$1
y=$2
printf "%d" $(($x/$y))
x=$(($x%$y))
x=$((100*$x))
printf ".%02d\n" $(($x/$y))

Sajnos igazad van. Én is csak olvastam, hogy van %f a printf-ben, nem próbáltam ki. Viszont ahol olvastam, ott hitelesnek tűnt a dolog. :)
Illetve pontosítok: figyelmetlenül próbáltam ki, nem tűnt fel, hogy olyannal osztottam, ahol eleve 0 a tizedesvessző utáni rész... :)

Hát így macerás és nem is igazán értem, hogy mi értelme lebegőpontos formátumot belerakni, ha nem tud számolni vele. :(

Értem én, hogy minden segédprogi plusz process.
Azt is értem, hogy bizonyos környezetekben ez "drága".

De akkor eleve hagyjuk a bash-t. Legyen tisztán bc. Vagy awk. vagy perl. bash nélkül.

Visszacsatolás eredeti felvetésemhez: kéne ismerni a pontos feladatot.
Lehet hogy az eredeti feladat megoldásában hatékonyabban tud segíteni a közösség, mint egy akadémiai gondolatkísérlet levezetésében.
(Hacsak az eredeti cél, nem maga az akadémiai gondolatkísérlet :D )
---
"A megoldásra kell koncentrálni nem a problémára."

Szervusz!

Pontosan ezért szeretném elkerülni külső program használatát. Pl. nálam a bc alapjáraton nincs telepítve. Sokkal hordozhatóbb a script, ha egy egyszerű osztás miatt (amit érzésre meg kell tudni oldani külső program nélkül is) nem követeljük meg egy másik program telepítését.


x=23456789; y=1024
r0=$((100*$x/$y)); len=${#r0}
int=${r0:0:$(($len-2))}; frac=${r0:$((len-2)):2}
r=${int:-0}.$frac; echo $r

Köszi, ez használhatónak tűnik! Először meg kell nézni, hogy az osztandó nagyobb - e, mint 1024 * 1024 *1024, vagy 1024 * 1024 vagy 1024, ennek függvényében az osztó 1024 * 1024 * 1024 vagy 1024 * 1024 vagy 1024. Ekkor a módszered szerint jöhet az osztás, a prefixum pedig az osztóval összhangban G, M vagy k.

Valami ilyen őrület?

x=654876546;
echo $(( $x>>10)).$((($x & 1023) * 100>>10))

Itt is kellene amugy valami elagazas, mert itt is megvan az a halmaz (10-102 kozott) ahol teves eredmenyt produkal. A megoldas viszont tetszetos ezt leszamitva :)
____________________________________
Az embert 2 éven át arra tanítják hogyan álljon meg a 2 lábán, és hogyan beszéljen... Aztán azt mondják neki: -"Ülj le és kuss legyen!"..

Idegesített engem ez a probléma, aztán kókányoltam egy ilyet fpc-vel:

http://sourceforge.net/projects/sh-math/files/sh-math/sh_math-1.0/

Gyakorlatilag csak paraméterelemzés -> számolás -> kiírás.

Előbb utóbb átírom c-re is :D

Használata:
sm_div 654654654 1024

vagy:
sm_rdiv 654654 1024 | sm_tostring -p

-fs-
Az olyan tárgyakat, amik képesek az mc futtatására, munkaeszköznek nevezzük.
/usr/lib/libasound.so --gágágágá --lilaliba

De ilyet azért nem tud:

tarolo:/usr/bin$ sm_tosys 16 178768768
AA7CB80
tarolo:/usr/bin$ sm_fromsys 16 AA7CB80
178768768

tarolo:/usr/bin$ sm_tosys 36 178768768
2YFMV4
tarolo:/usr/bin$ sm_fromsys 36 2YFMV4
178768768

-fs-
Az olyan tárgyakat, amik képesek az mc futtatására, munkaeszköznek nevezzük.
/usr/lib/libasound.so --gágágágá --lilaliba

Ezzel egyetértek, bár ha az "e" tudásánál bonyolultabb kell, akkor én előveszem a bc-t.

Egyébként ha a bash nem lenne olyan buta, akkor pl. a számrendszerek közti váltást simán meg lehetne ejteni úgy, ahogy a Korn-shell (*) pár évtizede már tudja:

$ typeset -i16 i=8#33 ; echo $i
16#1b
$

Azaz az i változóra beállítom, hogy 16-os számrendszerben tessen kezelni, majd értékül adom neki a 8-as számrendszerben értelmezett 33-t (ami ugye 27). A kiíratás pedig az adott változóra érvényes számrendszerben jelenik meg (amit persze jelez is). Vagy ha utólag jövök rá hogy konvertálni akarok, akkor csak átállítom az alapszámot, és kész.

Sajnos a bash nem ismeri a typeset -i esetén a számrendszer alapszámának megadását, ő csak 10-esben hajlandó megjeleníteni, de integer tipusú változónál a bash is hajlandó elfogadni a spéci formában levő bemenetet. Azaz ha elég a valamiből 10-esbe konverzió, akkor bash alatt is lehet így:

$ typeset -i i=8#33 ; echo $i
27

(Amúgy "bash" alatt "typeset"-ként kevéssé szokták ismerni, ott valamiért "declare"-nek szeretik hívni az adott parancsot - viszont mivel mind a kettőt megeszi, én jobb szeretem a hordozhatóbb formát használni.)

(*) ami a ksh93-s nevű verziójában amúgy float változótipust is kezel typeset -f v formában.

Végtére is: nem a parancsértelmező "dolga" a számolgatás. Futtatni tudjon, elágazást/ciklust szervezzen, stdin-t, stdout-ot kezeljen, számolóprogram meg van dögivel, úgyhogy "no problem" :)

-fs-
Az olyan tárgyakat, amik képesek az mc futtatására, munkaeszköznek nevezzük.
/usr/lib/libasound.so --gágágágá --lilaliba

Ciklusszervezesnel megis honnan lesz ciklusszamlalo leptetes? Szerintem eleg kevesen vannak ma mar, akik leirnak ilyeneket:

a=1
while [ "$a" -le 1000000 ] ; do
BLABLA
a=`expr "$a" + 1`
done

pedig itt pont az tortent, hogy az original Bourne-shell-nek nem volt aritmetikai muvelete, ezert aztan kenytelen volt az ember ilyen nyakatekert (es mint elottem mar jeleztek - iszonyat eroforraspazarlo modon) leptetni egy rohadt ciklusvaltozot.

Anno az eredeti Bourne-shellhez kepest a C-shell nagyon sok extra funkciot hozott be (iszonyat szarul implementalva, de mindegy), tobbseguk az interaktiv hasznalatot volt hivatott kenyelmesebbe tenni (history pl.), de bizony az ertekadashoz bevezetett @ parancs pontosan behozta az aritmetikai muveletvegzo kepesseget. Azt, hogy ez hasznos, mi sem bizonyitja jobban, mint az, hogy azota ez a lehetoseg minden shellben azota is letezik - legfeljebb nem a csh-ban bevezetett szintaxissal, lasd: (( a = a + 1 )) vagy a=$(( $a + 1 )) vagy a mar fent emlitett typeset -i a ; a=a+1 (jobb shellekben ezt is lehet ugy irni, hogy integer a, amugy)

Ezzel - az általam egyébként elfogadható - érvvel picit szembemegy a bashnek azon törekvése, hogy ezekbe a kategóriákba nem sorolható fícsöröket viszont agyontámogasson; amivel sikerült már odáig eljutni, hogy ember legyen a talpán, aki megmondja, hogy egy adott disztrib adott bash verziójának futása közben egy adott parancsnév után tabot nyomva mi fog történni.

echo 65535/1024 | bc -l

Én csak ezt a lehetséges módszert láttam eddig. Azon lepődtem meg, hogy a Linux kernel fordításához is kell a bc.

Egyéb praktikus lehetőség: perl vagy python szkript.

Anélkül, hogy végiggondoltam volna, szerintem nem jó. Az aktuális könyvtárba tudnék olyan nevű file-t tenni, amitől elromlik.

Az x=10*$((x-h*y)) kifejezésben az első csillag shell globbing. Vagy backslash kell a csillag elé, vagy idézőjelezni kellene, megfelelő helyekre az aposztrof is jó, legvégső esetben az x értéke akár ki is számolható. Mert így az x értéke egy string, amely ugyan kiszámolódik a következő helyettesítéskor, de kiszámolódhatna rögtön az x értékadásakor is.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Hmm, ha jól értelmezem, akkor ez attól függ, hogy az integer attribútummal rendelkezik-e az x változó. Az én bash verzióm úgy tűnik, az aritmetikai kifejezés miatt az egész értékadást aritmetikainak értékeli. (A x=10*x valóban hibás, kivéve, ha deklaráltuk a változót: declare -i x, ekkor elvileg a $(()) sem kell.)
De hogy ne legyen kérdéses:
x=$((10*(x-h*y)))

Így van. Nézzük ezt a példát:

x=8; h=2; y=3
x=10*$((x-h*y))
echo $x

10*2

Ellenben:

x=8; h=2; y=3
: >10a2
x=10*$((x-h*y))
echo $x

10a2

Ráadásul hibát sem generál, ha a globbing szám nevű filenév, például 1035912.

Neked azért működött, mert a glob nem illeszkedett semmire, ilyenkor a bash a *-ot literálisként helyettesíti. A másik dolog, hogy az így kapott string - jelen példában 10*2 - a következő körben az aritmetikai kifejezésbe helyettesítődött, ahol egyben kiszámolódott. További szerencséd, hogy a szorzás magasabb precedenciájú az összeadásnál, így még el sem számolta magát. :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE