Hello, megint én... :)
Szóval elkezdtem csinálni konkrét (iskolai) feladatokat shell scriptinggel, de pár feladattal elakadtam, és a gugli sem és a manual sem segített igazán.
Első ami ilyen, hogy kell egy számsort kiírni 1-től 100-ig, amiben csak a párosak szerepelnek. Nos addig eljutottam, hogy az összes számot hogyan kéne:
"for (( i=1; i<=100; i++ )); do echo $i; done". Ez tök jól kidobálja a terminálba a számokat, de arra sehogy sem jöttem rá, hogy a számtani sorozat differenciáját hogyan kéne beiktatni.
Aztán van egy olyan feladat, hogy meg kell adni, hogy mely paranccsal található meg a /usr-ben a "legmélyebb" könyvtár. Majd az utolsó olyan, hogy a /usr-ben lévő összes fájl kumulatív eloszlását kell kell elkészíteni és azt ábrázolni GNUPlottal log-log skálán, majd egy ponton hatványfüggvényt kell illeszteni.
Az a baj, hogy sehol sem találok hozzá megfelelő segítséget és jó lenne, ha meg tudnám oldani ezeket órán is.
Aki segít, annak örök hálám!
Üdv,
Tomato
UPDATE: A feladatokat megoldottnak tekintem. Köszönöm szépen mindenkinek a sok segítséget, tanácsokat, tippeket-trükköket! Sokat tanultam ma!
- 3182 megtekintés
Hozzászólások
Ez nem lenne jó?
for ((i=2; i<100; i+=2 )); do echo $i; done
Amúgy hol, mit tanulsz?
- A hozzászóláshoz be kell jelentkezni
Tökéletes, köszönöm szépen. :)
Amúgy fizikusnak tanulok az ELTE-n.
-Tomato
- A hozzászóláshoz be kell jelentkezni
a legegyszerubb megoldas: seq 2 2 100
- A hozzászóláshoz be kell jelentkezni
Ezt nem is ismertem ! Kössz ! :)
- A hozzászóláshoz be kell jelentkezni
Ezt viszont max. egy egs-sel jutalmaznám :-P mert ugyan a feladatot megoldotta, de a shell használata nélkül. És hogy egy kevésbé shellfüggő (bash, pdksh eszi szépen) megoldást (Zahy örömére) is mutassak...:
x=0
while [[ ${x} -lt 100 ]]
do
x=$(( ${x}+2 ))
echo $x
done
- A hozzászóláshoz be kell jelentkezni
szerintem ebben van három felesleges behelyettesítés...
#! /usr/bin/ksh
x=0
while [[ $x -lt 100 ]]
do
x=$(( x+2 ))
echo $x
done
ezt is eszi a pdksh és a sima sh-ként hívott bash is.
- A hozzászóláshoz be kell jelentkezni
Igen, eszi, csak bantuban az sh a dash-ra egy symlink, hogy franc ami beléje áll... (És az meg nem eszi a [[-t )
- A hozzászóláshoz be kell jelentkezni
bizony, multkor vagy egy oram rament, mire rajottem hogy miert nem mukodik egy tok egyszeru shell parancs...
egyre jobban utalom az ubuntut az ilyen barom megoldasok miatt...
- A hozzászóláshoz be kell jelentkezni
A $x leirasatol nekem borsodzik a hatam. A ${x} a helyes irasmod. Nagyon ritkan, ha olyan a script eredetileg es csak keves modositast csinalok benne, en is leirok egy $VALAMI-t, de akkor se szeretem.
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Bash-only...
- A hozzászóláshoz be kell jelentkezni
A második feladatra rávezetés (a teljes megoldás rád vár, de ha nem megy, kérdezz nyugodtan):
man find:
"-printf format
%d File’s depth in the directory tree; 0 means the file is a command line argument.
%p File’s name.
-type c
d directory"
Használható hozzá a sort parancs numerikus rendezéssel, és a head (vagy tail) az egy sor kivágásához.
- A hozzászóláshoz be kell jelentkezni
egy favágó megoldás könyvtármélységre:
find /usr/ -type d| sed -e 's,[^/],,g'| sort | tail -1 | wc -c
ebből kettőt le kell vonni, mert a /usr elején a / a 0. szint és mert van egy newline karakter is a végén.
utána a
find /usr -mindepth $melyseg -type d
megmondja, hogy mely könyvtárak ezek
ez:
find /usr -type f| sed -e 's,\(.*\)/\([^/]*$\),\1,'| sort | uniq -c | sort -n
meg elég favágó módon csinál egy listát, hogy melyik könyvtárban hány fájl van.
- A hozzászóláshoz be kell jelentkezni
A find szerintem elég "költséges" processz, duplán meg pláne, de legyen :)
find /usr/ -mindepth $(( $(find /usr/ -type d 2>/dev/null | sed -e 's,[^/],,g'| sort | tail -1 | wc -c)-2)) \
-type d 2>/dev/null
- A hozzászóláshoz be kell jelentkezni
favágóként bevezetett megoldásra tökéletes. favágónak nem adhatok meg optimalizált verziót:)
- A hozzászóláshoz be kell jelentkezni
Miután a könyvtárak becsüccsentek a cache-be, utána már nem volt lassú :-) Nekem egyébként tetszik, szép, write only móka :-P
- A hozzászóláshoz be kell jelentkezni
Nem kell kétszer a findet lefuttatni: egy tee-vel ki kell menteni a find kimenetét egy átmeneti fájlba, a pipe folytatásában megszámolni a perjeleket soronként, aztán paste-vel a két fájlt összemásolni két oszlopba, és végül az eredményt rendezni.
- A hozzászóláshoz be kell jelentkezni
Szóval mktemp foobarbaz? Minthogy szemetet nem hagyunk magunk után, így a script elejéről nem maradhat el a trap, megfelelően paraméterezve.
- A hozzászóláshoz be kell jelentkezni
de még inkább named pipe
amúgy jópofa hogy a fizikus szeretne egy regressziót fájlméretekre és néhányan teljesen irrelevánsan micsoda élvezettel szórakoznak szkirptirással :)
- A hozzászóláshoz be kell jelentkezni
Másik feladat :) A matematikázást meghagyjuk a számtanosoknak :-P
- A hozzászóláshoz be kell jelentkezni
nem számít, gondoltam a legnehezebb feladatot szúrom ki példának :)
- A hozzászóláshoz be kell jelentkezni
Az utolsó feladatnál a fájlok méretének eloszlását kell ábrázolni?
A fenti find -printf alapú megoldás kis módosítással erre is jó, aztán a kapott listát rendezd numerikusan és mentsd el egy fájlba. Ez triviális.
Ami nem triviális, az a hatványfüggvény illesztése.
A gnuplot illesztő algoritmusa kényes sok mindenre, többek között arra is, ha a paraméterek nagyságrendje között nagy eltérés van.
Úgy célszerű megadni a függvényt, hogy f(x) = (x/a)**b.
Az illesztésnél pedig ajánlott kijelölni azt a tartományt, ahol tényleg teljesül a hatványfüggvényszerű viselkedés. Ehhez kénytelen vagy ábrázolni az eloszlást, megnézni, hogy a log-log skálán nagyjából hol egyenes-szerű a görbe, és azt a tartományt a megadni a fitnek, pl így:
fit [25000:220000] f(x) 'usrsizes.txt' u 0:1 via a,b
Nálam b = 2.67 :)
Az ábrázolásnál pedig vedd az yrange-t mondjuk [0.5:*]-ra, hogy a logaritmikus skála ne ugasson a 0 méretű fájlok miatt.
- A hozzászóláshoz be kell jelentkezni
Köszönöm szépen az eddigi segítségeket.
Ilyet is sikerült összehalásznom:
find . -printf '%d\n' | sort -n | tail -1
Azzal a gnuplotossal az a baj, hogy az első részét nem igazán értem. vagyis hogy mit kéne kezdeni pontosan. :( Esetleg tudsz bővebben segíteni?
Köszi Mindenkinek!
-Tomato
- A hozzászóláshoz be kell jelentkezni
itt azért nem ártana elmondani, hogy általában unix vagy kifejezetten valamelyik mostani modern linux disztribúcióról van szó. nekem van egy olyan érzésem, amit most nem tudok bizonyítani, hogy nem mindegyik find tudja ezeket.
- A hozzászóláshoz be kell jelentkezni
Ubuntu 8.10
-Tomato
- A hozzászóláshoz be kell jelentkezni
Mármint minek az első részét nem érted, és mivel akarsz mit kezdeni? :)
Először is: a fájlok méretének az eloszlását kell ábrázolni?
A fenti parancssorod ehhez majdnem jó, csak %d helyett %s és a végén tail helyett irányítsd át a kimenetet egy fájlba.
(Tipp: ne find .-ot használj az /usr-ből, hanem find /usr-t és dolgozz a home könyvtáradban.)
Utána gnuplot, és help logscale, help plot, help plot using.
Ha abszolút semmit nem tudsz a gnuplotról, akkor olvasgass róla, hidd el, később nagyon hasznos lesz.
Kezdetnek egy tömör (és sajnos elavult) magyar leírás: http://rail.ttk.pte.hu/kmatyas/meresiadatcd/dokumentacio/gnuplot_magyar…
- A hozzászóláshoz be kell jelentkezni
Erre mit mondasz?
find /usr -printf '%s\n' | sort -n >file.txt
gnuplot
set log xy
plot "file.txt"
f(x) = (x/a)**b
fit [60000:70000] f(x) 'file.txt' u 0:1 via a,b
Közben megint csak köszönöm az újabb megoldásokat! Rendesek vagytok! :)
-Tomato
- A hozzászóláshoz be kell jelentkezni
Igen, erre gondoltam. Utána célszerű együtt plottolni az adatokat és az illesztett függvényt, hogy tényleg illeszkedik-e.
A gnuplot parancsokat pedig be lehet írni egy fájlba, lehet címet és tengelyfeliratot adni az ábrának és el lehet menteni eps-be, és akkor lesz igazán szép a megoldás.
- A hozzászóláshoz be kell jelentkezni
Így folytattam:
plot f(x), "file.txt"
set terminal png color
set output "abra.png"
replot
set terminal x11
set output
Itt meg a kép az egyenesről: http://img405.imageshack.us/i/abra.png/
mit szúrhattam el?
-Tomato
- A hozzászóláshoz be kell jelentkezni
Nézd meg, hogy a log-skálázott x tengelyen a [60000:70000] intervallum hova esik, és mekkora helyet foglal el.
Nekem az ábra alapján úgy tűnik, hogy arra a tartományra illik a függvény.
Ha ez a tartomány volt megadva a feladatban, akkor készen vagy. Ha nem, és neked kell megválasztani a tartományt, akkor jobban jársz a [4000:20000] vagy [20000:60000] tartományokkal, vagy e kettő uniójával.
"Nonlinear fitting is an art", ahogy bölcs emberek mondták. Itt az történik, hogy neked van egy primitív modelled (egy sima hatványfüggvény) az adatok leírására, de ez a modell túl egyszerű, nem adja vissza azok minden tulajdonságát.
Ránézésre látszik, hogy van két tartománya az eloszlásnak, amikre a hatványfüggvényes modell egész jó, de két különböző kitevővel. Az egész adatsorra viszont egyáltalán nem jó a modell.
Ha ez egy valós fizikai probléma lenne, akkor új, bonyolultabb modellt kellene keresned. Például egy olyat, ami két különböző kitevőjű hatványfüggvényből áll egy küszöbértékkel, ami elválasztja a kettőt. Ha ez érdekel, akkor nézd meg a gnuplot.info-n a demok között az illesztéseket: ott van példa ilyen tört függvény illesztésére.
- A hozzászóláshoz be kell jelentkezni
Köszi szépen, ismét! :)
-Tomato
- A hozzászóláshoz be kell jelentkezni
find /usr -type d | awk -F\/ '{print NF, $0}' -ból ki lehetne indulni...
most=0
for i in $(find /usr/ -type d -print | awk -F\/ '{printf "%d_%s\n", NF, $0 }' | sort -nr )
do
set $(echo $i | sed 's/_/\ /')
if [ $1 -ge $most ]
then
echo $2
most=$1
fi
done
Ezzel az összes olyan könyvtárat kiírod, aminek maximális a mélysége.
- A hozzászóláshoz be kell jelentkezni
Ha már ilyen szépen megszületett a kész megoldás, akkor én is leírom, amire az elején csak utalni próbáltam (ez csak egyet ír ki az esetleges több azonos közül):
find /usr -type d -printf "%d %p\n" | sort -nr | head -n 1
- A hozzászóláshoz be kell jelentkezni
A printf GNU-find only.
- A hozzászóláshoz be kell jelentkezni
Jogos, és nem a te munkádat akartam kritizálni (az enyém csak egyet ad meg, a tiéd az általánosabb megoldás). Viszont tudjuk, hogy Ubuntu a célrendszer, így szerintem kihasználható ez a tudása.
- A hozzászóláshoz be kell jelentkezni
Kihasználható, persze, viszont jó, ha tudja a hallgató, hogy erősen eszközfüggő megoldásról van szó.
- A hozzászóláshoz be kell jelentkezni
Javítva:
( most=0
for i in $(find /usr/ -type d -print 2>/dev/null | awk -F\/ '{printf "%d_%s\n", NF, $0 }' | sort -nr )
do
set $(echo $i | sed 's/_/\ /')
if [ $1 -ge $most ]
then
echo $2
most=$1
else
exit
fi
done )
- A hozzászóláshoz be kell jelentkezni
jessszus:)
először is az awk az, amit utoljára használnék hordozhatóra tervezett programban, mert az még linuxok között sem egyforma. A debianban is van mawk, nawk meg gawk, ezek közül a gawk a legótvarosabb.
egy echo-t meg egy sed-et forkolni minden sorra egy olyan embertől, aki szerint a find drága művelet, hát nem is tudom:)
ha már ilyen barbár módon csinálod, akkor
while read p1 p2
és úgy állapítom meg hogy nagyobb-e a most-nál.
de mivel az awk-kal már úgyis halálra bonyolítottad, ezért érdemesebb az awk-ban megcsinálni, hogy ami kisebb, azt ki se írja.
ja, ha dash sh-ra van linkelve, akkor köteles sh-ként működni, ha nem, akkor bugreport
Ha nagyon szép megoldást szeretnénk, akkor az IFS-t /-re cserélve, read-del tömbbe beolvastatva a könyvtárneveket, a tömb méretére van bash beépített függvény, az megmondja, milyen mély a könyvtárstruktúra. A konkrét megoldást az olvasóra bízzuk:)
- A hozzászóláshoz be kell jelentkezni
És a () meg az exit nem is tűnt fel :-) Ennél szebbet első körben hallgatótól nem várnék el, ha nagyon trükkös, akkor kilóg a lóláb :-)
- A hozzászóláshoz be kell jelentkezni
aki nem tudja, tanítja:PP
- A hozzászóláshoz be kell jelentkezni
Ennél szebbet első körben diáktól nem várnék el, ha nagyon trükkös, akkor kilóg a lóláb :-) A set $(echo $i | sed...) valóban randa, egy set ${i/_/ } sokkal szebb :) Az awk-kal valóban óvatosan kell bánni, azonban ezt a kiírást azért illik tudnia :-)
- A hozzászóláshoz be kell jelentkezni
nem próbáltam ki, de miért is nem iratod ki úgy awk-kal a sort, hogy utána ne kelljen sed-ezni benne?
a gawk nálam akkor szerepelt le, mikor volt egy olyan kiadott éles verziója, ami a hexa számjegyek közül a 3 legnagyobbat nem tudta:P
- A hozzászóláshoz be kell jelentkezni
Ilyen alapon az openssl-t se használd, mert annak is volt egy olyan verziója, ami... :-)
- A hozzászóláshoz be kell jelentkezni
Igy elsore:
FILENAME=/tmp/tempfile_$$
find /usr/ -type d -print > $FILENAME
MOST=`awk -F/ '{if ( most < NF ) { most = NF }} END {print most}' $FILENAME`
awk -v most="$MOST" -F/ '{if ( most == NF ) { print $0 }}' $FILENAME
rm $FILENAME
- A hozzászóláshoz be kell jelentkezni
Így elsőre:
-A tempfile_$$ biztos, hogy egyedi?
-Ha nyomok egy ctrl-C bármikor, a szemetét otthagyja -- a trap hiányzik.
- A hozzászóláshoz be kell jelentkezni
Igazad van!
TEMPFILE=/tmp/enyime_es_tuti_hogy_egyedi_de_ha_megtalalod_torold_le_nyugodtan_$$
if [ -e $TEMPFILE ]
then
TEMPFILE=/tmp/basszus_az_elozo_letezett_$$_de_ez_tuti_nem_$$
fi
trap "rm $TEMPFILE" SIGINT SIGTERM
find /usr/ -type d -print > $TEMPFILE
MOST=`awk -F/ '{if ( most < NF ) { most = NF }} END {print most}' $TEMPFILE`
awk -v most="$MOST" -F/ '{if ( most == NF ) { print $0 }}' $TEMPFILE
rm $TEMPFILE
Ezeket csakazert nem raktam bele, mert marcsaka csicsazas, a feladat mar az a 4 sor megoldotta.
A tempfilet csak shell tombbel lehetne helyettesiteni, hogy jo is legyen, de annyit szerintem most nem er.
Szerintem ezzel meg is oldottam a problemat:
- A hozzászóláshoz be kell jelentkezni
mktemp(1)
TMPFILE=`mktemp /tmp/example.XXXXXXXXXX` || exit 1
- A hozzászóláshoz be kell jelentkezni
Az awk interpretált nyelv, emiatt lassú. Van, hogy a sort gyorsabb, mégha pazarlóbb is.
- A hozzászóláshoz be kell jelentkezni