Lenne pl egy fileban valamilyen szaparátorral (pl: '\n') elválasztott IP címek. Hogyan tudnék véletlenszrűen kiválasztani egyet egy bash script-tel.
- 2283 megtekintés
Hozzászólások
Pontos megoldast hirtelen nem tudok, en igy jarnam be a fajlt...
cat iplista.txt | while read line;do
ip=`echo $line`;
done
Ebben az $ip valtozo egy ip, amivel barmit csinalhatunk most... csak kell valami random... agyalok, de gondoltam addig ideirom hatha masnak segit...
- A hozzászóláshoz be kell jelentkezni
én elsőkörben erre gondoltam:
max_sor=`wc -l iplista.txt | cut -f1`
line=`echo $RANDOM` # na itt nem tudom, hogy lehet megadni mi a max
ip=`cat iplista.txt | head -$line | tail -1`
Várok minden ötletet
- A hozzászóláshoz be kell jelentkezni
Pl igy:
IPLIST=($(cat iplist.txt))
N=${#IPLIST[*]}
R=$RANDOM
x=$((R%N))
IP=${IPLIST[x]}
(az iplist.txt-ben sortoressel (megengedo") vagy szokozokkel vannak elvalasztva az ip-cimek)
A.
- A hozzászóláshoz be kell jelentkezni
köszi, kicsit átalakítottam, így teljesen szuper :)
- A hozzászóláshoz be kell jelentkezni
Erről jut eszembe, nagyon jópofa kis matek példa, és elég meglepő hogy meg lehet csinálni.
Jön egy baromi hosszú sorozat (mondjuk akár újsorral elválasztott IP-címek egy pipe-on keresztül), nem tudod előre hogy milyen hosszú, viszont sokkal hosszabb annál minthogy legyen esélyed eltárolni az egészet és utólag feldolgozni. Más szóval: baromi kevés memóriád van, és csak egyszer olvashatod el az inputot. A feladat ilyen körülmények között kiválasztani egy uniform random elemet.
Bónusz feladat: ha a matek példa megoldása megvan, akkor lekódolni bash-ben :)
- A hozzászóláshoz be kell jelentkezni
1. Ha az elso" elemet olvasod be, beleteszed a kimeneti valtozoba.
2. Ha az N-ik elemet olvasod be, akkor 1/N valoszinuseggel beleteszed a kimeneti valtozoba (azaz dobsz egy 0 es N kozotti valos szamot, es ha 1-nel kisebb, akkor).
3. vege van a stream-nek: a kimeneti valtozo lesz a kivalasztott random elem.
Ez igy tul egyszerunek is hangzik ;)
N=1
while read data ; do
cat /dev/urandom | \
head -c 8 | \
hexdump -d | \
head -n 1 | \
awk -v N=$N \
'{ x=0;
for ( i=2 ; i<=NF ; i++ )
{ x=(x+$(i))/65536.0; }
if ( N*x<=1 ) exit(0);
else exit(1);
}' && OUT="$data"
N=$((N+1))
done < data.txt
echo $OUT
- A hozzászóláshoz be kell jelentkezni
Így van.
Nem semmi bash+awk mágiát dobtál össze :-) Azon gondolkodom, lehet-e lényegesen egyszerűbben, de nem hinném. Innen kezdve ízlések és pofonok... (Az eredeti elképzelésemben simán $RANDOM-ot használtam volna, de az bizony csak nagyon rövid inputokra jó.)
Vicces hogy a hexdump progit használod decimális szám kiírására, én pedig az od-t (octal dump) szoktam használni hexához. :D
Amit én tákolnék össze, az nagyjából úgy nézne ki, hogy a /dev/urandom byte-jait az
od -A n -t x1 | tr -d ' '
parancs hexásítja, amit még nagybetűssé kell alakítani, mert a bc-nek csak úgy lesz jó, sőt, akkor már helyette talán a egyszerűbb a
hexdump -v -e '1/1 "%02X"'
(hú, mire ezt összehoztam a manual alapján... nem csoda hogy nem szoktam hexdumpot használni), majd ha ez az érték a $K változóban van, az $N pedig az ami a te progidban is, akkor
echo "n=$N; ibase=16; k=$K; n%k" | bc -q
kimenetét kell megnézni hogy nulla-e, és ha igen, akkor frissíteni OUT-ot.
Valszeg ez az a feladat, amit józan ember nem bash-ben implementál :-)
Bónusz bónusz feladat igazi mazochistáknak: mind apal megoldása, mind az én megoldásom a rengeteg fork+exec miatt baromi lassú (minden bemeneti adatra jut több is). Normális programnyelven persze bárki le tudja kódolni ezt. Kódoljuk le bash-ben kizárólag beépített függvényekkel, külső program meghívása nélkül! :-)
- A hozzászóláshoz be kell jelentkezni
Tenyleg szebb es gyorsabb igy :)
cat data.txt | \
while read data ; do
k=1
o=0
while true ; do
M=$((32768))
R=$RANDOM
#M=$((32768*32768))
#R=$((32768*RANDOM+RANDOM))
d=$((k*M-N*R))
if [ "$d" -ge $N ] ; then
o=1
break
elif [ "$d" -lt 0 ] ; then
o=0
break
else
k=$d
fi
done
[ $o -gt 0 ] && echo "$data"
N=$((N+1))
done | \
tail -n 1
(ha tobb mint 32k a varhato sorok szama, akkor a masodik M= es R= ertekadast kell hasznalni, bar igy is huzos a tulcsordulas, egesz szamoknal, persze azt is ki lehet hasznalni hogy a modern bash-oknal 64bites mar a $((...)) operacio).
Ja igen, es ez igy mar mukodik ugy is hogy pipe-rol, az elozo neme ment volna ugy :]
A.
- A hozzászóláshoz be kell jelentkezni
Az a baj, hogy a $RANDOM egy nagyon primitív pszeudorandom: a következő érték egyértelműen megmondható az előző alapján. A /dev/(u)random szerintem nem hagyható ki a játékból.
Az első leküzdendő feladat: végtelen stream-ből véges hosszan olvasni tisztán bash-ben. A "read -r -d '' -n N" konstrukciónál jobbat nem találtam. Ez változóba teszi le az értéket, és változóban nullás byte nem lehet, ilyenkor ott megszakad az értéke, ezért ciklusba kell tenni és addig olvasni, amíg a kívánt mennyiségű adat meg nem jött. Tesztelendő, hogy az egyéb byte-okat mind jól kezeli-e, és a locale függvényében nem kezd-e el hülyeségeket csinálni (például UTF-8-ként értelmezni) - remélem nem.
Most jönne az a lépés, amikor egy byte-ot kellene átalakítani az ASCII kódjává, vagy bármely más módon egy random byteból vagy bytesorozatból egy számot előállítani. A tipikusan ord-nak hívott függvény bash megfelelőjére nem találtam rá. Nagyon gagyi megoldásként lehet valami iszonyú hosszú if-elif-elif-elif... ágat csinálni az átalakításra. Vagy spórolhatunk a kóddal ha pazaroljuk az inputot, például csak az A és B betűket vesszük figyelembe és ezekből építünk fel 2-es számrendszerben egy nagy számot, de a /dev/(u)random értékes entrópiából dolgozik, nem illik vele ilyen módon pazarolni.
Ha ez a lépés megvolna, akkor a többi már könnyedén megy.
Még egy apró megjegyzés: A generált véletlen egész lehetséges értékeinek száma aligha többszöröse az éppen aktuális N-nek. Ha teljesen pontos uniformot akarunk, akkor bizonyos esetekben új számot kell sorsolnunk. Példa: ha 0-2-ig kell véletlenszám, és egy 0-255-ig véletlenszámgenerárunk van, akkor mondhatjuk simán hogy modulo 3, de akkor a nullás valószínűsége icipicit nagyobb lesz. Erre nincs lényegesen jobb megoldás, mint jelen példában 255-ös érték esetén új véletlenszám sorsolása.
- A hozzászóláshoz be kell jelentkezni
Az a baj, hogy a $RANDOM egy nagyon primitív pszeudorandom:
Akkor lehet irni egy viszonylag jobbat ;) A seed-et az elejen a /dev/[u]random-bol veszi (az lehet bonya, hexdump, awk) es kihasznaljuk hogy 64bites a $((...)). Ebbol igy mar teljesen jol tud dolgozni.
Pl az lrand48() manualja meg is adja hogy az a 48 bites randomgenerator milyen konstansokat hasznal. Oke, ez sem tokeletes, de egy bonyolultabb randomgenerator is hasonlo aritmetikakat tartalmaz, azt meg meg lehet irni shell-ben.
Még egy apró megjegyzés: A generált véletlen egész lehetséges értékeinek száma aligha többszöröse az éppen aktuális N-nek.
Ezt az esetet kezeli a szkript, azert van while true ... ; do kozott, es nem csak egy sima maradek (egyszeru" novekmenyes algoritmus, mint pl. az egyenes rajzolasa pixel-ra'csra). Ha az R tenyleg tok random akkor a sorok szama 1 es M-1 kozott barmi lehet, korrekt modon fog dolgozni, egyenletes eloszlast ad vissza akkor is.
A.
- A hozzászóláshoz be kell jelentkezni
> Ezt az esetet kezeli a szkript
Jogos, nem néztem meg ennyire alaposan hogy mit csinálsz.
Közben megszületett az ord implementációm (képzeletben) bash-ben. Először csinálunk egy változót, aminek az értéke az 1-255 byte-ok egymás után. Ez mehet hard-coded módon: x=$'\001\002...@ABCD...\377', vagy generálható ciklusban a "printf %c $n" trükk használatával.
Ha ez megvan, akkor pedig jöhet a végéről lecsípő operátor: ha $c a karakter, akkor "${x%$c*}" lecsípi x végéről a $c-t és az azt követő részt, a maradékot adja vissza, aminek már csak a hosszát kell lekérdezni a ${#...} szintaxissal.
Még az sem kizárt, hogy ezzel a módszerrel a nullás input byte-ot sem kell eldobni. Ha $c-be olvasunk, akkor ez esetben ő nulla hosszú lesz, így a lecsípés+hosszszámítás után 255-öt kapunk, míg igazi karakter esetén 0-254-et (ord mínusz 1), szóval megvan a teljes 0..255 intervallum.
Szerk: printf-et félreismertem, visszavonom.
- A hozzászóláshoz be kell jelentkezni
> Most jönne az a lépés, amikor egy byte-ot kellene átalakítani az ASCII kódjává, vagy bármely más módon egy random byteból vagy bytesorozatból egy számot előállítani. A tipikusan ord-nak hívott függvény bash megfelelőjére nem találtam rá.
$ typeset -i x
$ x=36#abcd
$ echo $x
13368
Mondjuk nem teszteltem, hogy Ctrl-X meg egyéb (nem nyomtatható) karakter esetén mit csinál.
- A hozzászóláshoz be kell jelentkezni
Hm, egyebkent erre a problemara deb alatt van egy `randomize-lines` csomag,
rl
nevu" binarissal. Az `rl --count 1` ezt csinalja, pontosan, es nem zabal fel memoriat ;) Kerdes: hogyan kell az algoritmust modositani, hogy tetszoleges K db (K elore rogzitett) sort adjon vissza, 1/ mindegyiket max egyszer 2/ egy sor szerepelhet tobbszor is...
- A hozzászóláshoz be kell jelentkezni
(törölve, bocs)
- A hozzászóláshoz be kell jelentkezni
Nincs véletlenül egy 'random' nevű segédprogram épp erre a célra?
- A hozzászóláshoz be kell jelentkezni
Hat, egy idoben kellett volna nekem is nagyon (inkabb adat-feldolgozas temakorhoz, tehat valos szamokat, mindenfele eloszlas szerint kellett, hogy generaljon), de mar egy sima egesz szamos valtozat se volt...:/
- A hozzászóláshoz be kell jelentkezni
Gányoltam gyorsan egyet, bár a topiknyitó házifeladatához szerintem nem lesz jó;)
http://web.axelero.hu/lzsiga/random.tgz
gcc -o random random.c defs.c
./random /etc/passwd
- A hozzászóláshoz be kell jelentkezni
Igen, ezt irtam fentebb is, hogy erre a problemara valamilyen progit/csomagot irtak: randomize-lines. Azt hittem eloszor hogy veletlenszam-generatorra gondoltal. Olyan sincs, leszamitva a shell $RANDOM-jat, ami meg nem tul jo/altalanos...
- A hozzászóláshoz be kell jelentkezni
sort -R
(bocs ha wo vagyok)
- A hozzászóláshoz be kell jelentkezni
Nem rossz, de egy
cat input | sort -R | head -n 1
tetszolegesen sok memoriat felvehet es/vagy sok tmpfile-t hozhat letre, az eredeti problemat viszont ordo(1) memoriaval lenne jo megoldani.
- A hozzászóláshoz be kell jelentkezni
Indokolja valami hogy bashban legyen az egész? Én tuti kiraknám a random generálást egy standalone alkalmazásba. Ha a fork-exec lassulás miatt aggodsz, sztem az megoldható valami named-pipe-on keresztül, amit a random process etet, a bash meg olvasgat.
A GSL-ben pl. van egy két pszeudórandom generátor, de ha nem akarsz dependency-t magaddal cipelni, akkor is ki lehet operálni valahonnan egy jó generátort. [ha kell el tudom küldeni a numercial_recipes ran0,ran1,ran2,ran3,ran4 generátorokat függőségek nélkül kioperálva, ha még megtalálom, mert régen használtam]
Vagy félreértettem valamit?
- A hozzászóláshoz be kell jelentkezni
Indokolja valami hogy bashban legyen az egész
Az eredeti, felvetett problemara ez teljesen jo megoldas ;] (ha a $RANDOM nem elegge random akkor egy kis hexdump+/dev/random-mal ra lehet segiteni).
Egmont kollega altal felvetett problema mar mas kerdes, de ha csak egyedi esetekrol, nem massziv alkalmazasrol es relative rovid fileokrol van szo, akkor kis bash hax is tokeletesen megfelelo", arra a problemara is, szerintem.
A.
- A hozzászóláshoz be kell jelentkezni