7. Laboratóriumi gyakorlat, 1. rész : Vezérlési szerkezetek II. A gyakorlat célja: 1. A shell vezérlő szerkezetei használatának gyakorlása. A használt vezérlő szerkezetek: if/else/fi, for, while while, select, case, shift. 2. A ${} sztring operátorainak használata 3. A (( )) számításokat elősegítő szerkezet használata Előkészülethez szükséges anyag: a 6. és 7. előadás segédlete és a felhasznált parancsok kézikönyv lapjai illetve rövid leírásai. A gyakorlat menete: 1. Az if szerkezet...1 2. A for ciklus...2 3. A read parancs...2 4. A while és until szerkezetek...3 5. A case szerkezet és a shift...4 6. Sztring operátorok a ${} szerkezetben...4 7. Számítások a (( )) szerkezettel...5 Megoldott feladatok...5 1. Az if szerkezet Írjunk szkriptet amelyik... 1.... if szerkezettel eldönti, van-e legalább egy argumentum a parancssoron. Ha van, akkor kiírja az argumentumok számát. 2.... kiírja, hogy két argumentuma közül az első vagy a második a nagyobb mint szám. Ha nem adunk meg pontosan 2 argumentumot hibaüzenettel kilép. 3.... az argumentumában megadott állományról kiírja, hogy olvasható, írható ás végrehajthatóe a felhasználó által. Ha a jogok nincsenek beállítva, azt írja ki, hogy nem olvasható, stb. 4.... ha a parancssoron megadott állomány könyvtár, kiírja, hogy könyvtár, belép a könyvtárba, és kilistázza a benne levő állományok nevét. ha nem könyvtár, akkor csak az állományra ad listázást. Mindkét esetben mielőtt listázna, kiírja, hogy mit fog csinálni. 5.... ha a parancssoron megadott állomány olvasható és írható, akkor kilistázza az állomány utolsó 10 sorát, és utána az állomány végére írja, hogy "Listázva". Ha nem teljesül mindkét feltétel, akkor kiírja: "Rossz jogok az... állományon." (pontok helyett az állomány neve). 6.... ha a parancssor első és negyedik argumentuma mint sztring egyenlő, kiírja: "rossz argumentumok". 7.... ha a parancssor 4. argumentuma zéró hosszú sztring, kiírja: "4. argumentum zéró hosszúságú" 1
Írjunk egy szkriptet amelyik kiírja, hogy első argumentuma kisebb vagy nagyobb mint a parancssoron levő több argumentum! (tehát legalább 2 argumentumot kell neki megadni, de lehet akár tízet is). 2. A for ciklus Az alábbi kis szkripteknek SOHA SEM SZABAD ROSSZ ARGUMENTUMOK MIATT HIBÁZNIUK, ezért: minden hibalehetőséget tesztelni kell, és ha szükséges le kell állítani a szkriptet a hiba kiírásával és zérótól különböző kilépési kóddal. Írjunk egy szkriptet, amelyik... 1.... végigjárja a munkakönyvtárunk állományait, és kiírja nevüket. Módosítsuk ezt a szkriptet az alábbiakkal: -Ne a munkakönyvtárt, hanem az első parancssori argumentumban megadott könyvtárat járjuk végig. -Ne csak a nevüket írjuk ki, hanem azt is ha olvashatóak. -Ha a végigjárt állomány könyvtár írjuk a neve után zárójelbe, ugyanabba a sorba (könyvtár). 2.... amelyik létrehozza az argumentumaiban megadott nevű könyvtárakat a munkakönyvtárunk alá. Ha nem adunk meg argumentumokat, vagy valamelyiket nem lehet létrehozni, hibát ír ki. Írja ki minden alkalommal amikor sikerült egyet létrehozni. 3.... kiírja a számokat 1-től 10-ig és utánaírja az összegüket. Módosítsuk, hogy a parancssoron megadott 2 argumentum közti számokat és azok összegét írja ki. A seq parancsot fogjuk használni a számok generálására. 4.... a /etc/passwd állományban levő felhasználóneveket járja végig. Csak azokat írja ki ahol a felhasználó login vevének hossza pontosan 4. A shell alatt egy változó hosszát több módon kiszámolhatjuk, pl. a user változó hosszát kiírhatjuk az alábbi echo parancsokkal (a sorok elején levő $ jel a shell készenléti jele): $ user="eva" $ echo ${#eva} 3 $ echo -n $user wc -c 3 5.... végigjárja a parancssoron megadott könyvtár állományait. Ha közönséges állományt talál kiírja a nevét. ha könyvtárat, akkor belép és végigjárja az ott levő állományokat, ugyancsak a nevüket írja ki. Utána visszalép az első szintre. Hogyan írnánk meg egy olyan szkriptet, amelyik "akárhány" szintig elvégzi az előbieket? 6.... végigjárja egy kis szöveges állomány sorait. Pl. töltsük le a words1 állományt és járjuk végig és írjuk ki a benne levő szavakat egy for ciklussal. Írjuk ki csak az 5 karakter hosszú szavakat. 3. A read parancs Olvassuk át a read parancs kapcsolóit a segédletből és végezzük el a következőket: 2
1. Olvassuk be egy változóba az alábbi sorokat (külön-külön): a abc def abc def ghi 2. Olvassuk be két változóba ugyanazokat a sorokat. Mit tapasztalunk? 3. Írjunk ki készenléti jelet (pl. "Írj be egy sort:") a read -el! 4. Olvassunk be csak egy karaktert a read-el egy változóba! 5. Írjunk programot, amely végigolvas a read-el egy szöveges állományt úgy, hogy az állomány sorai külön-külön feldolgozhatóak egy while ciklus belsejében! 6. Ellenőrizzük, mennyi a read visszatérítési értéke ha állomány vége jelet ütünk be olvasáskor ( ^D )? 4. A while és until szerkezetek Írjunk kis ciklusokat amelyek az alábbiakat valósítják meg: 1. Olvassunk be sorokat a terminálról és írjuk vissza a sorok hosszát addig amíg EOF karakter ütünk be. Módosítsuk a programot úgy, hogy addig olvasson sorokat amíg egy kis a betűt ütünk be. Adjunk erre a feladatra 2 megoldást. 2. Írjunk egy ciklust amelyik addig várakozik 2 másodperces sleep parancsokat végrehajtva, amíg az 1.txt nevű állomány létrejön. utána kilép a ciklusból és kiírja: "1.txt megjelent!". Írjuk meg a programot: -while ciklussal -until ciklussal A teszteléshez egyik terminálon futtatjuk a szkriptet, a másikon pedig a touch -al létrehozzuk az 1.txt állományt. 3. Járjuk végig egy állomány sorait úgy, hogy egy olyan szkriptnek, amelyik while read line do #feldolgozás done típusú feldolgozást tartalmaz a standard bemenetére egy szöveges állományt irányítunk. Végigjárás közben írjuk ki a.) a sorok számát a sorok elé és a sorokat b.) a sorok számát és a sorban levő szavak számát a sorok elé 4. Egy állomány sorait végigjárva találjuk meg a leghosszabb sort és írjuk ki azt a while ciklus befejeztével. 3
5. A case szerkezet és a shift 1. Írjunk egy olyan szkriptet amely a case szerkezet segítségével írja ki nekünk, hogy milyen billentyűt ütöttünk be: kisbetűt, nagybetűt, számjegyet vagy egyéb karaktert. A program olvasson egy ciklusban egyenként karaktereket a read-el, addig amíg EOF jelet nem kap. 2. A lista.txt (letöltés) állományban termékkódok és darabszámok vannak valamilyen raktári nyilvántartásból. Készítsünk egy héjprogramot, amely kódok szerint szétválogatja 3 állományba a sorokat: az elsőbe azok kerülnek, amelyeknél a kód P-vel kezdődik és kisbetűvel folytatódik valamint azok amelyek a kód Q-val kezdődik, a másodikba azok amelyek P-vel kezdődnek, második betűjük pedig szám, valamint azok amelyek R-el kezdődnek, a harmadikba azok amelyek P-vel kezdődnek és a második betűjük nagy betű. A három állomány neve 1.txt, 2.txt és 3.txt. Mindhárom végére oda kell még "ragasztani" egy sort, amelyben az szerepel, hogy az illető állományban hány sor van van. A program írja ki azt is, ha talál olyan sort, amelyet nem tud osztályozni. 3. Teszteljük le a parancssor paramétereit a case struktúrával: milyen kapcsolók vannak rajta? Legyenek pl. -a, -b, -c kapcsolók egy program számára, és a -b kapcsolónak legyen egy kötelező paramétere. Például az alábbi programindításnál: prog.sh -a -b x -c arg1 a program írja ki: a kapcsoló b kapcsoló és argumentuma x c kapcsoló az arg1 az elso kapcsoló nélküli argumentum A kapcsolókat mindig az argumentumok előtt adjuk meg. Használjuk fel a shift parancsot is a tesztelés írásakor. 4. Írjuk ki egy while szerkezettel a parancssor minden második paraméterét a shift -et használva. 6. Sztring operátorok a ${} szerkezetben 1. Írjuk be egy állomány teljes elérési útját egy változóba, pl: file='/home/eva/teszt.txt' Írjuk ki echo paranccsal: -csak az állomány nevét 4
-a könyvtár nevét amelyben található, teljes elérési úttal -az elérési utat alkotó könyvtárak nevét külön-külön -az állománynév kiterjesztését. 2. Írjunk olyan programot amely átnevez minden.sh típusú állományt.bash típusúvá egy könyvtárban. Az állomány típus karakterláncának leválasztásakor használjuk fel a ${} belsejében alkalmazható karakterlánc operátorokat. A program legyen nagyon biztonságos: nehogy véletlenül is elvesztődjenek az állományok az átnevezés alatt. 7. Számítások a (( )) szerkezettel 1. Írjunk egy olyan szkriptet amelyik a terminálról olvas 2 számot (n1, n2), és utána n1 ciklust végez, mindegyik ciklusban beolvas egy harmadik számot (n3). Ha n3 egyenlő n2-vel hagyjuk abba a ciklust. 2. Számoljuk ki egy szkripttel, hogy egy könyvtárban levő állományokban összesen hány byte és kilobyte van. 1 kilobyte-ot 1024 byte-nak számolunk. Megoldott feladatok A programok a pelda7.tgz állományban vannak. Kipakolás: $ tar -xzv -f pelda7.tgz 1. Olvassunk végig egy szöveges állományt. Miközben kiírjuk a sorokat a terminálra, írjuk a sorok elé a sor számát, utána pedig a sorban levő karakterek számát ( sorok.sh ). 2. Írjunk egy programot amely végrehajthatóvá teszi az argumentumaiban megadott állományokat egyenként. Minden művelet előtt nézze meg, hogy az illető állomány létezik-e., utána kérdezze meg minden egyes létező állománynál, hogy végezze-e el a műveletet vagy nem: i vagy n karakterekkel válaszoljunk a kérdésre ( toexec.sh ). 3. Adjuk össze a számokat 1-től n-ig az expr és seq parancsot használva! (summa.sh) 4. Szűrjük ki a '\r' (kocsi vissza) karaktereket egy adott könyvtárban levő adott típusú forrásállományokból (.c,.java. stb. típusú állományok). A szűrés után az állományok maradjanak ugyanolyan név alatt ugyanabban a könyvtárban (dosunix.sh). Megjegyzés: a Linux alatt létezik egy dos2unix program, mint parancs, amelyik megoldja ezt a feladatot parancsszinten, lásd man dos2unix. 5. Írjunk egy programot, amely kilistázza egy shell szkript első sorait, mindaddig míg a sorok első karaktere a # (help.sh). 6. Írjunk egy programot amelyik egy könyvtárból kilistázza az ott található szöveges (.txt típusú) állományok első és utolsó sorát, valamint a sorainak számát. Az 1.txt nevű állomány esetében, amelynek első sora abc, utolsó pedig xyz és 22 sort tartalmaz, a kimenet így nézzen ki: File: 1.txt : 22 sor E: abc U: xyz 5
(a példaprogram firstlast.sh). 7. Írjunk egy programot, amelyik megszámolja, hogy a $PATH változóban levő könyvtárakban összesen hány bináris futtatható állomány van. A $PATH tartalma például nálam így néz ki: /usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/. A következőket csináljuk: -átírjuk a kettőspontokat szóközzé, majd a listát egy változóhoz rendeljük -végigjárjuk a listát és kilistázzuk az egyes könyvtárak tartalmát ls -1 paranccsal -a wc és expr programokkal megszámoljuk, hogy hány állomány van a listákban A program neve binfiles.sh. 6