„EDU::GAMF::Operációs rendszerek::Gyakorlatok” változatai közötti eltérés

Innen: Farkas Attila Wiki
Ugrás a navigációhoz Ugrás a kereséshez
 
(11 közbenső módosítás ugyanattól a szerkesztőtől nincs mutatva)
963. sor: 963. sor:
| ^e || Nem || nincs a sor elején e betű
| ^e || Nem || nincs a sor elején e betű
|-
|-
| . || Igen || Bármilyen karakter lehet a sor végén
| .$ || Igen || Bármilyen karakter lehet a sor végén
|-
|-
| \. || Igen || . van a sor végén
| \. || Igen || . van a sor végén
1 009. sor: 1 009. sor:
| ^.\+$ || Igen || Mindenre illeszkedik, kivéve az üres sorra
| ^.\+$ || Igen || Mindenre illeszkedik, kivéve az üres sorra
|}
|}
A következő kifejezés szintén illeszkedik:
^[A-Z].*\(egy\)\|\(kettő\).*\.$ => A sor elején nagybetűvel kezdődik, van a közepén valahol benne "egy" vagy "kettő" karakterlánc és ponttal végződik. A köztes karakterek értéke nincs megszabva.
==== grep ====
==== grep ====
A '''grep''' utasítás segítségével végezhetünk el reguláris kifejezés, tehát minta illesztést fájlokon. Amennyiben nem adunk meg fájl paramétert, a STDIN csatornát olvassa. Az eredmények a STDOUT-ra íródnak.
{| class="wikitable" style="margin: 0px auto"
|+ Fontosabb kapcsolók
|-
! Rövid név !! Hosszú név !! Magyarázat
|-
| -c || --count || Megszámolja az illeszkedő sorokat
|-
| -o || --only-matching || Csak a mintára illeszkedő részt írja ki (nem a teljes sort)
|-
| -n || --line-number || Megszámozza a sorokat (a fájl alapján, nem a megjelenítés szerint)
|}
===== Példa =====
<syntaxhighlight lang="bash">
# nologin környezetet futtató felhasználók listája a rendszerben
grep "nologin" /etc/passwd
cat /etc/passwd | grep "nologin" # STDIN-en érkező adatok szűrése
# bash környezetet futtató felhasználók listája a rendszerben
grep "bash" /etc/passwd
cat /etc/passwd | grep "bash"    # STDIN-en érkező adatok szűrése
</syntaxhighlight>
===== Példa 2 =====
Írjunk egy scriptet, amely a /bin/bash futtatási környezetet kapó felhasználók nevét kiírja a képernyőre.
<syntaxhighlight lang="bash">
#!/bin/bash
# a fájl, amin dolgozunk
file="/etc/passwd"
# a fájl sorainak száma
lines=`cat $file | wc -l`
# végig megyünk a fájl sorain
for i in `seq 1 $lines`; do
# itt kapjuk meg az i. sort
line=`head -$i $file | tail -1`
# kiszedjük a shell környezetet
shell=`echo $line | cut -f7 -d':'`
# ha ez "/bin/bash", akkor kivágjuk a sor első oszlopát, ezt írhatjuk a képernyőre
if test $shell == "/bin/bash"; then
  echo $line | cut -f1 -d':'
fi
done
</syntaxhighlight>
A fenti script futási ideje: 0.227s
<syntaxhighlight lang="bash">
#!/bin/bash
# a fájl, amin dolgozunk
file="/etc/passwd"
# szűrjük ki a sorokat, amelyeknek a végén a "/bin/bash" karakterlánc található
#  és a kapott eredményhalmaznak vágjuk ki az első oszlopát
# a kapott eredményhalmaz még mindig megfelel a /etc/passwd eredeti formátumának,
#  csak a sorok számát csökkentettük a szűrési feltételnek megfelelően!
grep "/bin/bash$" $file | cut -f1 -d':'
</syntaxhighlight>
A fenti script futási ideje: 0.003s
===== MAC cím parser =====
Legyen egy MAC címeket tartalmazó fáljunk - mac-cimek.txt:
<syntaxhighlight lang="bash">
00:0C:42:AB:CD:EF
00:0c:42:ab:cd:ef
00-0C-42-AB-CD-EF
00-0c-42-ab-cd-ef
000c42abcdef
000C42ABCDEF
00:0C:42:AB:CD:EF:AB
00:0C:42:AB:CD:EF:
0G:0C:42:AB:CD:EF
00.0C.42.AB.CD.EF
00:0C:42:AB:CD:EG
</syntaxhighlight>
Ebben a fájlban vannak megfelelő és hibás szintaktikájú címek is. A feladat, hogy készítsünk reguláris kifejezést, amely megjeleníti a helyeseket a képernyőn.
<syntaxhighlight lang="bash">
grep "^\([[:xdigit:]]\{2\}[-:]\?\)\{5\}[[:xdigit:]]\{2\}$" mac-cimek.txt
</syntaxhighlight>
Érdekességképp beletehetünk a fájlba a MAC címek elé és/vagy után véletlenszerű (megjeleníthető) karaktereket.
Mit tapasztalunk? Miért?
Távolítsuk el a sor eleje és a sor vége illesztéseket és futtassuk a grep-et a -o kapcsolóval? Mi változik?
(''grep -o "\('''['''[:xdigit:]''']'''\{2\}[-:]\?\)\{5\}'''['''[:xdigit:]''']'''\{2\}" mac-cimek.txt'')


== 4. óra ==
== 4. óra ==

A lap jelenlegi, 2024. október 9., 13:15-kori változata

1. óra

Az első óra a tantárgy és annak követelményeinek ismertetésével kezdődik, majd egy-két alap utasítást tekintünk meg. Ezután a programok csatornáival folytatjuk.

Parancsok és példák

man

A man parancs segítségével megtekinthetjük egy-egy alkalmazás, parancs, esetleg külső könyvtár függvényeinek dokumentációját.

Használata: A program neve után írhatjuk, hogy melyik alkalmazás, parancs vagy esetleg külső könyvtár függvényének dokumentációját szeretnénk megtekinteni. Megtekinthetjük ily módon a man parancs használati útmutatóját is a következő utasítás kiadásával:

man man

Hasonló módon alkalmazhatjuk bármelyik parancsra, amelyek ezen a weboldalon felsorolásra kerültek. Pl. a head utasítás dokumentációját az alábbi módon érhetjük el

man head

ls

Érdemes megtekinteni a parancs dokumentációját a man ls utasítás kiadásával, tisztában legyünk ez elérhető kapcsolókkal és funkciókkal.

Az ls parancs segítségével listázhatjuk a mappa tartalmát. Alapértelmezetten a ., tehát a jelenlegi könyvtárat listázza.

# meghívás paraméter nélkül
ls

# meghívás . paraméterrel - ugyanaz az eredmény
ls .

A listázni kívánt könyvtár nevét megadhatjuk paraméterben:

# root könyvtár listázása
ls /

# a /usr/local/bin könyvtár listázása
ls /usr/local/bin

Érdemes megjegyezni a hosszú formátumú kiírást, aminek segítségével a fájlrendszer bejegyzések jogosultságait és méretét kérhetjük le.

# Jelenlegi könyvtárban listáz minden elemet és azok tulajdonságait
ls -l

# A /bin/ls fájl jogosultságainak lekérdezése
ls -l /bin/ls

Próbáljuk ki, hogy ha egy mappa nevével futtatjuk le a parancsot, akkor az ls megnyitja a könyvtárat és annak tartalmát listázza ki.

# a /bin könyvtár tartalma listázódik, nem a /bin könyvtár maga
ls /bin

Ez különösen akkor okoz problémát, ha például az adott könyvtár jogosultságait szeretnénk megtekinteni. Ekkor két választási lehetőségünk adódik:

# A felette lévő könyvtárat listázzuk és kikeressük a megfelelő bejegyzést
ls / -l

# használjuk a -d kapcsolót, aminek segítségével felszólítjuk az ls-t, hogy ne nyissa meg az adott könyvtárat
# Ekkor a könyvtár listázódik, nem a tartalma
ls -d /bin

pwd

A pwd parancs segítségével lekérdezhetjük annak a könyvtárnak az abszolút elérési útvonalát, amelyben éppen benne vagyunk.

A parancsot főleg arra használjuk, hogy aktuálisan mellettünk elhelyezett fájlok és könyvtárak abszolút útvonalát ki tudjuk alakítani.

pwd

cd

A cd parancs segítségével könyvtárat válthatunk (changedir). A cél könyvtár nevét paraméterben kell megadnunk.

# root könyvtár megnyitása
cd /

# HOME könyvtár megnyitása
# ~ egy alias
cd ~

# /usr/bin megnyitása
cd /usr/bin

A hivatkozásoknál, így a cd esetében is lehetőségünk van relatív és abszolút hivatkozásokat használni:

  • Az abszolút hivatkozás / elérési út mindig / jellel kezdődik. pl.: cd /home/, cd /usr/bin
  • A relatív hivatkozás vagy nem rendelkezik kezdőkarakterrel: cd home, cd bin, vagy . illetve .. karakterekkel kezdődnek.
    • A . könyvtár jelenti az aktuális könyvtárat
    • A .. könyvtár jelenti a szülő könyvtárat
# szülő könyvtár megnyitása
cd ../

# a szülőkönyvtárban található bin könyvtár megnyitása
cd ../bin

# az aktuális könyvtárban található bin könyvtár megnyitása
cd ./bin
cd bin      # vegyük észre: a ./ ez esetben elhagyható

mkdir

Az mkdir parancs segítségével könyvtárakat hozhatunk létre (make directory). Alapértelmezetten a . könyvtáron (tehát ahol éppen tartózkodunk, azon a könyvtáron) belül hozza létre az új mappát, de lehetőségünk van mind relatív, mind abszolút hivatkozások használatára.

# folder könyvtár létrehozása az aktuális könyvtárban
mkdir folder
mkdir ./folder2
# subfolder létrehozása a folder könyvtáron belül.
mkdir folder/subfolder

# létrehozás a /tmp könyvtáron belül, akárhol is vagyunk
mkdir /tmp/folder

# folder létrehozása a szülőkönyvtárban
mkdir ../folder

A fentebb leírtak alapján egyetlen könyvtárat hozhatunk létre, egy már létező könyvtáron belül, legyen az éppen az, amiben tartózkodunk, vagy valahol máshol a fájlrendszerben. Azonban előfordul, hogy egyszerre több mappát szeretnénk elkészíteni, például egy mélyebb struktúrát szeretnénk kialakítani, mint ami a rendelkezésünkre áll. Ezt természetesen megtehetjük úgy, hogy az egyes szinteket egyesével hozzuk létre, de alkalmazhatunk kapcsolót, amelynek segítségével a nem létező szülőkönyvtárakat is létrehozza, amennyiben nem léteznek.

# root könyvtáron belül létrejön egy ''test'' könyvtár és azon belül jön létre a ''folder'' könyvtár.
mkdir /test/folder/ -p

# az aktuális könyvtárban jön létre egy ''test'' könyvtár és azon belül a ''folder'' könyvtár
mkdir -p test/folder

# a jelenlegi könyvtárban létrejon a ''test'' könyvtár, 
# azon belül létrejön egy ''folder1'' és egy ''folder2'' könyvtár, 
# majd mind a kettőben létrejön a ''work'' könyvtár.
mkdir -p test/{folder1,folder2}/work

Természetesen ahhoz, hogy egy könyvtárban további fájlokat vagy könyvtárakat hozzunk létre jogosultság szükséges.

rmdir

Az rmdir parancs segítségével üres könyvtárakat törölhetünk.

Figyelem! Ha a könyvtár nem üres (fájlok vagy egyéb könyvtárak találhatók benne, akkor hibaüzenetet kapunk és nem csinál semmit!

# relatív hivatkozással
rmdir test/folder

# abszolút hivatkozással
rmdir /test/folder

cp

A cp parancs segítségével fájlokat és könyvtárakat másolhatunk a fájlrendszer egy pontjáról a másikra.

# /etc/passwd fájl lemásolása a jelenlegi könyvtárba - ls paranccsal ellenőrízhető
cp /etc/passwd ./

# /etc/passwd lemásolása a jelenlegi könyvtárba és közben átnevezés file-ra
cp /etc/passwd ./file

# /etc/passwd lemásolása a /tmp könyvtárba
cp /etc/passwd /tmp/

# /etc/passwd lemásolása a /tmp könyvtárba és közben átnevezés file-ra
cp /etc/passwd /tmp/file

Könyvtárak másolása esetén a -r kapcsoló használata szükséges (recursive).

# /etc/network könyvtár és annak tartalmát másolja a /tmp könyvtárba
cp /etc/network /tmp/ -r

mv

Az mv parancs segítségével fájlokat és könyvtárakat mozgathatunk. Ezzel a paranccsal nevezhetjük át a fájlrendszer elemeit.

A próbálkozáshoz másoljuk le a /etc/passwd állományt, ha eddig nem tettük meg!
cp /etc/passwd ./
# passwd állomány átnevezése file-ra
mv passwd file

# nem fut le!
# /etc/passwd állomány átnevezése file-ra
mv /etc/passwd /etc/file

# nem fut le!
# /etc/passwd állomány áthelyezése /tmp-be
mv /etc/passwd /tmp

# nem fut le!
# /etc/passwd állomány áthelyezése /tmp-be és közben átnevezés file-ra
mv /etc/passwd /tmp/file

A könyvtárak áthelyezéséhez (vagy átnevezéséhez) ez esetben nincs szükségünk a recursive (-r) jelölésre.

rm

Az rm parancs segítségével fájlokat és könyvtárakat törölhetünk.

rm file

Könyvtárak törléséhez alkalmaznunk kell a rekurzív jelölést: -r.

rm folder -r

less

A less egy fájlnézegető, amelynek segítségével lapozhatunk billentyűzet segítségével a fájlokban.

less /etc/passwd

more

A more szintén egy fájlnézegető, de ennek segítségével csak előre lapozhatunk, visszafelé nem.

more /etc/passwd

which

A 'which program segítségével lekérdezhetjük, hogy az adott utasításhoz tartozó állomány melyik mappában található.

# az ls parancs abszolút elérési útvonala
which ls

# a which parancs abszolút elérési útvonala
which which

# a man parancs elérési útvonala
which man

file

A file utasítás segítségével lekérdezhetjük, hogy egy adott állomány milyen típusú: futtatható állomány (ELF), ASCII stb.

file /etc/passwd
file /bin/ls

echo

Az echo mindent kiír a képernyőre, amit parancssori argumentumként adunk át neki.

echo "Hello World"
echo Hello World
echo Ez egy teszt üzenet
echo "Ez egy teszt üzenet"

Láthatjuk, hogy idézőjeltől függetlenül minden megjelenik a képernyőn. Észrevehetjük azt is, hogy minden sor végén új sor karakter (enter) található, amit a "-n" kapcsoló segítségével kapcsolhatunk ki.

echo -n "Hello world"

cat

A cat utasítás fájlokat képes összefűzni és az eredményt a képernyőre írja ki.

# /etc/passwd és a /etc/profile fájlok összefűzése a képernyőn (ebben a sorrendben)
cat /etc/passwd /etc/profile

Egy gyakoribb felhasználási módja, hogy a fájlok tartalmát a képernyőre vessük - ez esetben nem fűzünk hozzá semmit a fájlhoz.

# /etc/passwd és a <semmi> összefűzése és megjelenítése a képernyőn
cat /etc/passwd

head

A head utasítás segítségével a fájlok első N során írhatjuk ki a képernyőre. Alapértelmezetten N=10, így ha csak egy fájlnevet adunk neki, akkor annak legfeljebb 10 sorát fogja kiírni (ha van annyi).

head /etc/passwd

Az alapértelmezett N=10 értéket a -n kapcsoló segítségével módosíthatjuk

head -n 5 /etc/passwd

# a -n a dokumentáció elhagyható, ha a - után szám található
head -5 /etc/passwd

tail

A tail hasonlóan működik, mint a head, de ez esetben nem a fájl elejéről ír ki N sort, hanem a végéről.

tail /etc/passwd

Az alapértelmezett N=10 értéket a -n kapcsoló segítségével módosíthatjuk

tail -n 5 /etc/passwd

# a -n a dokumentáció elhagyható, ha a - után szám található
tail -5 /etc/passwd

wc

A wc utasítás segítségével statisztikai adatokat nyerhetünk ki egy fájlból (word counter): sorok, szavak, karakterek és bájtok száma.

wc /etc/passwd

Van lehetőségünk szűkíteni a visszaadott adatokat kapcsolók segítségével:

Rövid kapcsoló Hosszú kapcsoló Leírás
-l --lines sorok számát adja vissza
-w --words szavak számát adja vissza
-c --chars karakterek számát adja vissza
--bytes bájtok számát adja vissza
# sorok számát írja ki
wc -l /etc/passwd
# szavak számát írja ki
wc -w /etc/passwd
# bájtok számát írja ki
wc --bytes /etc/passwd

# sorok és szavak számát írja ki a képernyőre
wc -l -w /etc/passwd

find

A find utasítás segítségével kereshetünk a fájlrendszerben különböző attribútumok alapján.

# passwd nevű fájl keresése a /etc könyvtárban
find /etc -name passwd

Programok csatornái

STDIN

STDOUT

STDERR

Pipeline

Parancsbehelyettesítés

Feladatok

Szedjük ki a /etc/passwd állomány 20. sorát

# beolvassuk az első 20 sort és levágjuk az utolsót
head -20 /etc/passwd | tail -1

Mondjuk meg egy keresett bináris típusát

# fájl elérési út lekérdezése
# STDOUT => /bin/ls
which ls

# fájl típusának lekérdezése
file /bin/ls

# rakjuk össze:
file `which ls`

2. óra

A második órát az alap utasításokkal folytatjuk. Utána scriptek írásával foglalkozunk, amelyben megtekintjük a különböző vezérlési szerkezeteket is.

Parancsok és példák

mcedit

Az mcedit az mc (Midnight Commander) szerkesztője. A Midnight Commander testvére a Total Commander ősének, a Volkov Commandernek, ami szintén egy konzolos alkalmazás. A közös gyökerek miatt nagyon hasonló funkcionalitásokat érhetünk el ebben is, mint a TC-ben - érdemes megnyitni az mc utasítással, amit később az F10 billentyűvel, vagy az alsó sorban arra a gombra kattintással tudunk bezárni. Ebben az alkalmazásban működik az egér is, így kényelmes használatot eredményez. Érdekesség, hogy a "tálcára helyezés" is megoldott, így a Ctrl+O billentyűkombinációkkal háttérbe küldhetjük és folytathatjuk dolgunkat a terminálon, majd ugyanezzel a kombinációval előtérbe is hívhatjuk.

Az mcedit megnyitható az mc-ből is, a szokásos F4-es billentyűvel - vagy az arra való kattintással.

Az egér az mcedit-ben is működik!

A másolás a szerkesztőben is hasonlóan működik, mint a kétpaneles fájltallózóban: F5 és F6 billentyűkkel másolhatunk illetve áthelyezhetünk sorokat. Kilépni az F10 billentyűvel, ESC-el tudunk, de ezt az ablakot is a háttérbe küldhetjük, ha szerkesztés közben terminált szeretnénk elérni (CTRL+O).

mcedit /etc/passwd

nano

A nano szintén egy szövegszerkesztő alkalmazás.

Alul láthatjuk a segédletet, hogy milyen kombinációkkal milyen funkcionalitás érhető el. A szükségesebbek:

  • CTRL+K segítségével kivághatunk sorokat a vágólapra (shift+kurzorbillentyűk segítségével tört sorok is kijelölhetők)
  • CTRL+U Beilleszti a vágólap tartalmát az aktuális sorba
  • CTRL+O Menti a változásokat
  • CTRL+X Kilép, de megkérdezi, hogy menteni akarunk-e, ha vannak mentetlen változások
nano /etc/passwd

chmod

shift

cut

A cut parancs segítségével táblázatos adatokat szűrhetünk: kiválaszthatjuk, hogy mely oszlopokat szeretnénk megjeleníteni. A két legfontosabb kapcsolója a -f (field), ahol a megjelenítendő oszlopokat adhatjuk meg és a -d (delimiter), ahol az elválasztó karaktert állíthatjuk be.

Általában a /etc/passwd állományon dolgozunk, mert ebben egy :-al elválasztott táblázat található.

# a fájl első oszlopát szedi ki :-nál elválasztva, 
# tehát a felhasználónevet
cut -f1 -d':' /etc/passwd

# a fájl első és harmadik oszlopát adja vissza :-nál elválasztva, 
# tehát a felhasználónevet és az id-ját
cut -f1,3 -d':' /etc/passwd

# a fájl első három és hatodik oszlopát adja vissza :-nál elválasztva,
# tehát a felhasználónevet, jelszót és a felhasználó id-ját, valamint a home könyvtárát
cut -f1-3,6 -d':' /etc/passwd

sort

A sort utasítás segítségével rendezhetjük az adattömböt.

# a passwd állomány rendezése a felhasználónév szerint - ez van elől
sort /etc/passwd
# fordított sorrend - reverse
sort -r /etc/passwd

Alapértelmezetten karakterek szerint rendez, tehát a számokat tartalmazó adatsorokat nem helyes sorrendben adja vissza. Ha számérték szerinti rendezést szeretnénk végrehajtani, akkor használjuk a -n opciót.

# file egy számokat tartalmazó fájl - egy sor egy fájl
sort -n file
# fordított sorrend
sort -r -n file

tr

A tr parancs segítségével karaktereket cserélhetünk ki egy fájlban. Ezen kívül nagyon hasznos tulajdonsága, hogy a kívánt ismétlődéseket el tudja távolítani, mintegy megtisztítva az adatsort.

# az e betűt o-ra, az o betűt e-re cseréli ki
echo "hello" | tr eo oe

# A T betűt K-ra, az n betűt p-re cseréli ki
echo "Tanar" | tr Tn Kp

A fenti példák alapján nézzük meg, hogy mi történik:

  1. A tr két pozicionális paraméterrel lett meghívva
    1. Az első paraméter adja meg a lecserélendő karakterek halmazát
    2. A második paraméter adja meg az új karakterek halmazát
  2. A program végig megy a bemeneten és közben megvizsgálja, hogy az adott karakter megtalálható-e az első paraméterben
    1. ha megtalálható, akkor lecseréli a karakterrel azonos pozícióban álló második paraméterben található értékre
    2. ha nincs benne, akkor megy tovább
  3. a metodika miatt keresztbe is lehet cserélni (pl. o-t e-re, e-t o-ra, mint az első példában). Gondoljuk végig, hogy ha nem így lenne, akkor az először lecserélt e betűnek a végén o betűre kéne cserélődnie.

if

Az if segítségével elágazásokat hozhatunk létre, mint minden más programozási nyelven. A szerkezet a következőképp néz ki:

if KIFEJEZÉS
then
elif KIFEJEZÉS
elif KIFEJEZÉS
else
fi

Természetesen az egyes feltételek kihagyhatók, így készíthetünk egy egyszerű if elágazást is:

if KIFEJEZÉS
then
fi

Ha egy sorban szeretnénk leírni (nem scriptben), akkor a következőképpen tehetjük meg:

if KIFEJEZÉS; then UTASÍTÁS1; UTASÍTÁS2; elif KIFEJEZÉS; then UTASÍTÁS1; UTASÍTÁS2; else UTASÍTÁS; fi

KIFEJEZÉS
Egy olyan program, amelynek a visszatérési értéke hasznos információkat hordoz a futás eredményét tekintve. Ne feledjük el, hogy a return kulcsszóval tudunk ilyen értéket generálni C/C++ kódok esetében. Lássunk egy példát:

#include <stdio.h>

int main() {
  if ( 10 % 2 == 0 ) return 0;
  else return 1;
}

A fenti program visszatérési értéke információval szolgál számunkra, hogy a 10 osztható-e kettővel, avagy sem. Ez az érték vizsgálható az if segítségével és a válasz függvényében más-más kódokat hajthatunk végre.

A kiértékelés ellentétes a megszokott módszerhez képest (ahol minden igaz, aminek az értéke nem 0).

# ha a KIFEJEZÉS 0 értéket ad vissza, akkor IGAZ az állítás, tehát az if-en belüli kód fut
if KIFEJEZÉS => 0
then
  ....
else
  ....
fi

# ha a KIFEJEZÉS nem 0 értéket ad vissza, akkor HAMIS az állítás, tehát az else-n belüli kód fut
if KIFEJEZÉS => != 0
then
    ...
else
    ...
fi

A programozási nyelvek tanításakor ezért térünk vissza 0-s értékkel (return 0;), a programunk végén, és hiba esetén 1, vagy annál nagyobb értékkel.

test

A test parancs logikai függvényeket értékel ki és

  • 0 értéket ad vissza, ha az eredmény IGAZ,
  • 1 értéket ad vissza, ha az eredmény HAMIS

Az if utasítással együtt szoktuk használni, de természetesen ettől független is meghívható.

# megtörténik a logikai kiértékelés, eldől, hogy a két string egyezik-e
test "text1" == "text2"
# kiírjuk a képernyőre a test utasítás visszatérési értékét
echo $?

if utasítással a következőképp használhatjuk:

# hamis
if test "text1" == "text2"
then
  echo "igaz"
else
  echo "hamis"
fi

# igaz
if ! test "text1" == "text2"
then
   echo "igaz"
else
   echo "hamis"
fi

#igaz
if test "text1" != "text2"
then
   echo "igaz"
else
   echo "hamis"
fi

Elérhető egy alias, aminek segítségével olvashatóbbá tehetjük a test utasítást. Ez a [ ] pár.

if [ "text1" == "text2" ]
then
  echo "igaz"
else
  echo "hamis"
fi

Ügyeljünk rá, hogy a [ és a ] zárójelek mellett whitespace karakterek vannak. Ha ezeket kihagyjuk, akkor hibát fogunk kapni!

A számok ellenőrzése BASH környezetben körülményesebb, mivel itt minden karakterláncnak számít. Emiatt a következő utasítás sorozat nem várt eredménnyel zárul:

if [ "1000" <= "20" ]
then
  echo "igaz"
else
  echo "hamis"
fi

Az eredmény: igaz. De tudjuk, hogy ez az eredmény nem igaz, a BASH mégis így értékelte ki. Az oka, hogy az első karaktereket tekintve (1 és 2) elmondható, hogy az 1-es hamarabb van az ABC-ben (kódtáblában), mint a 2, így az 1000-nek kisebbnek kell lennie (mintha a "alma" és "körte" lenne összehasonlítva, hogy melyik következik előbb az ABC-ben).

Ahhoz, hogy a test utasítás karakterek helyett számként dolgozza fel a paramétert, kapcsolót kell használnunk:

Kapcsoló Angol megnevezés Magyar megnevezés
-eq Equals Egyenlő
-ne Not Equals Nem egyenlő
-lt Lower than Kisebb, mint
-le Lower than or equals Kisebb vagy egyenlő
-gt Greather than nagyobb, mint
-ge Greather than or equals Nagyobb vagy egyenlő
if [ 1000 -le 20 ]
then
  echo "igaz"
else
  echo "hamis"
fi

Az eredmény: Az elvártaknak megfelelően HAMIS.

for

A for utasítás segítségével egy lista elemein mehetünk végig. Hasonlóan működik, mint a modern programozási nyelvekben a foreach.

Legegyszerűbben a következő utasítással tesztelhetjük, ahol a bemeneti listát soronként látjuk viszont a képernyőn:

for i in 1 2 3 4 5 6
do
  echo $i
done

Természetesen van lehetőségünk a listát más program kimenetéből kinyerni a parancsbehelyettesítés segítségével:

for i in `ls`
do
  echo $i
done

A for gyakorlatilag a pozicionális paramétereken megy végig, tehát egy lista elem a $1, egy másik listaelem a $2. Tudjuk, hogy ha szóközök között adjuk meg, akkor szóközt is tartalmazhat a paraméterünk. Lássunk egy példát:

for i in "1 2 3" "4 5 6"
do
  echo $i
done

Ez esetben a képernyőn két sor jelenik meg: 1 2 3 és 4 5 6. Azonban a parancsbehelyettesítés nem alkalmaz az idézőjelhez hasonló technikát, tehát azt alkalmazva minden szó (szóközökkel határolt karaktersorozat) új pozicionális paramétert jelent. Lássunk egy az előzőhöz hasonló példát:

for i in `echo "1 2 3 4 5 6"`
do
  echo $i
done

Ez esetben hat sor jelenik meg, benne egy-egy számmal, tehát az echo "1 2 3 4 5 6" kimenetét szóközönként vágta fel.

while

A while utasítás, mint minden programozási nyelvben, itt is felfogható úgy, mint egy többször lefutó if. Éppen ezért a szintaktikájuk megegyezik, csupán a feltételek megírásával kell óvatosan bánnunk, hogy a ciklus mag akkor és addig fusson, ameddig mi azt szeretnénk. A while ciklusnál ugyanazokat az alkalmazásokat írhatjuk be a KIFEJEZÉS helyére, mint az if esetében.

while KIFEJEZÉS
do
done

Például ha azt akarjuk, hogy egy ciklus addig fusson, amíg meg nem jelenik egy fájl a fájlrendszerben, akkor azt a következőképp vezethetjük le:

# ellenőrzi, hogy a fájl elérhető-e
test -f "file.txt"

# ez esetben egyetlen kísérletet teszünk, de nem várjuk meg, hogy oda kerüljön, amennyiben nincs ott
if test -f "file.txt"
then
  echo "a fájl létezik"
else
  echo "A fájl nem létezik"
fi

# várakozunk, amíg a feltétel nem lesz igaz, tehát a fájl nem kerül oda
while ! test -f "file.txt"
do
  echo "várakozunk"
done
echo "a fájl létezik"

# test parancs helyettesítése []-el
while ! [ -f "file.txt" ]
do
  echo "várakozás"
done
echo "a fájl létezik"

A while ciklusnál érdemes megemlíteni a until utasítást, ami annyiban tér el, hogy a feltétel kiértékelését invertálni kell - tehát ami igaz a while esetében, az hamis az until esetében és fordítva. Így a fenti feladatot megvalósíthatjuk invertálás nélkül, az until utasítással is:

until test -f "file.txt"
do
 echo "várakozás"
done
echo "a fájl létezik"

seq

A seq utasítás egy listát generál számunkra, amelyben a megadott lépésszámmal, a megadott legkisebb értéktől a megadott legnagyobb értékig szerepelnek a számok.

# számok 1-10-ig
seq 10

# számok 5-10-ig
seq 5 10

# számok 3-tól 10-ig 2-esével
seq 3 2 10

A seq utasítást általában a for ciklus listájában használjuk, hogy elő tudjuk állítani az indexeket.

for i in `seq 3 2 10`
do
  echo $i
done

read

A read utasítás segítségével a STDIN-ről kérhetünk be információt változóba/változókba. Ha több változót sorolunk fel, akkor a bemenetet szóközöknél vágja el.

# beolvasás var-ba
# STDIN => teszt
#  var => teszt
# STDIN => teszt szöveg
#  var => teszt szöveg
read var

# beolvasás fname és lname változókba
# STDIN => Attila Farkas
#  fname => Attila
#  lname = Farkas
# STDIN => Attila
#  fname => Attila
#  lname => <üres>
# STDIN => Attila Farkas OPSYS
#  fname => Attila
#  lname => Farkas OPSYS
read fname lname

# beolvasás három változóba. Ha a felhasználó az utasításokkal szemben több szót adott meg, akkor így biztosíthatjuk, hogy ne legyen szóköz az első két változóban
# STDIN => Attila Farkas
#  fname => Attila
#  lname => Farkas
#  tmp => <üres>
# STDIN => Attila Farkas OPSYS meg valami más
#  fname => Attila
#  lname => Farkas
#  tmp => OPSYS meg valami más
read fname lname tmp

Az utóbbi esetben hibaüzenet is generálható, ha megvizsgáljuk, hogy a tmp változó értéke üres-e:

echo -n "Adja meg a teljes nevét: "
read fname lname tmp

# -n => nem üres?
# -z => üres?
if [ -n "$tmp" ]
then
  echo "Valamit elhibáztál"
  exit 1
fi

Ha szeretnénk ellenőrzött bekérést végrehajtani:

tmp="start value"
while [ -n "$tmp" ]
do
  echo -n "Adja meg a teljes nevét FNAME LNAME formátumban: "
  read fname lname tmp
  if [ -n "$tmp" ]
  then
    echo "Valamit elrontottál!"
    # ez esetben nem lépünk ki, mert bekérjük újra
  fi
done

expr

Az expr parancs segítségével tudunk matematikai műveleteket végrehajtani. Mivel a BASH-ben minden változó karakterlánc, így nem tudunk közöttük műveletet végezni. Az expr a paramétereket belül számként kezeli. Csak egész számokkal tud dolgozni!

# a képernyőre kerül az eredmény
expr 1 + 2
expr 4 * 4

# csak egész számot ír ki
expr 3 / 2

Ha tört számokkal kell dolgoznunk, akkor a következőket tehetjük:

  1. eltávolítjuk a törtrészt
  2. felszorozzuk 10^n-nel, ahol n a törtrész számjegyeivel egyezik meg (pl. 10.02-t 100-al kell szorozni). Az egész térben elvégzett művelet eredményét később vissza osztjuk ugyanannyival, amennyivel korábban felszoroztuk. Ez nem egy egyszerű feladat, hiszen a tört számot egyáltalán nem kezeli az expr, tehát cut, wc és egyéb parancsokkal kell kialakítanunk a számot, ahogy utána szét is kell darabolnunk azt.
  3. Másik környezetet használunk, ahol tudunk számokat is kezelni - ez a ZH-n nem elfogadott

A lehetőségek közül csak az elsőt, a ZH-n teljes mértékben elfogadott megoldást mutatom be:

# a 3.4-et és a 1.2-őt kell összeadnunk.

# ennek eredménye 3
echo "3.4" | cut -d'.' -f1

# ennek eredménye 1
echo "1.2" | cut -d'.' -f1

# rakjuk össze
expr `echo "3.4" | cut -d'.' -f1` + `echo "1.2" | cut -d'.' -f1`

Feladatok parancsokhoz

Írassuk ki a /etc/passwd több sorát

Több választási lehetőségünk van:

  • ha a kiírandó sorszámok valamilyen logikát követnek (minden második, harmadik stb.), akkor használhatjuk a seq utasítást
  • ha nincs logika a sorszámokban, akkor kézzel kell elkészítenünk a listát

Logikát tartalmazó sorszámok
Írassuk ki minden harmadik sor tartalmát

# határozzuk meg a seq tartományát
# min: 1
# max: ahány sora van a fájlnak

# max érték meghatározás
# a változó létrehozást lentebb tárgyaljuk
max=`cat /etc/passwd | wc -l`

# lista meghatározása for ciklushoz
# 1-től $max-ig hármasával
seq 1 3 $max

# Rakjuk össze
for i in `seq 1 3 $max`
do
  head -$i /etc/passwd | tail -1
done

Logikát nem tartalmazó sorszámok
Írassuk ki a 2., 5., 10. és 11. sorokat

for i in `2 5 10 11`
do
  head -$i /etc/passwd | tail -1
done

Fájlok ellenőrzése és másolása

Másoljuk át a /etc/passwd állományt egy könyvtárba (~/test/destination). Ha a célkönyvtár nem létezik, akkor hozzuk létre. Ha a célkönyvtár és a fájl is létezik, akkor írjunk ki hibaüzenetet.

# forrás fájl létezésének vizsgálata
test -f /etc/passwd

# célfájl létezésének vizsgálata
test -f ~/test/destination/passwd

# mappa létezésének vizsgálata
test -d ~/test/destination

# rakjuk össze

# ha a forrásfájl nem létezik
if ! test -f /etc/passwd
then
  echo "A forrásfájl nem létezik"
# ha a célfájl létezik
elif test -f ~/test/destination/passwd
then
  echo "A fájl már létezik"
# ha a cél mappa nem létezik
elif ! test -d ~/test/destination
then
   # mappa létrehozás - szülőkönyvtárakat is, ha nem léteznek
   mkdir -p ~/test/destination
   # fájl belemásolása
   cp /etc/passwd ~/test/destination
# ha a célfájl nem létezik, de a célmappa igen
else
   # a fájlt bemásoljuk a könyvtárba
   cp /etc/passwd ~/test/destination
fi

Script létrehozása

  • Script megírása
  • Futási jog

Pozicionális paraméterek

Változók

3. óra

A harmadik órán reguláris nyelvekkel foglalkozunk. A nyelv szintaktikai elemzése után a BASH-ben erre alkalmas szoftvert, a grep-et foguk megvizsgálni.

Reguláris kifejezés szerkezete

A reguláris nyelvek atomokból, lezártakból épül fel, amelynek az eredménye az úgynevezett „összetettek”.

Atomok

Az atomok egy karakterre illeszkednek a sorban.
Atom jelentés
betűk, számok saját magukra illeszkednek
^ sor elejére illeszkedik (csak egyszer lehet a legelején)
$ sor végére illeszkedik (csak egyszer lehet a legvégén)
[abc] halmaz: minden benne lévő elemre illeszkedik
[^abc] inverz halmaz: egyetlen benne lévő elemre sem illeszkedik
. mindenre illeszkedik

Lezártak

A lezártak ismétlődéseket fogalmaznak meg egy atomra vonatkozóan. Lezárt csak atom után helyezkedhet el!
Lezárt jelentés
* az atomot 0 és végtelen között akárhányszor ismételheti
+ az atomot 1 és végtelen között akárhányszor ismételheti
? az atomot 0 és 1 között akárhányszor ismételheti
{n} az atom pontosan n-szer fordul elő egymás mellett
{n,m} az atomot n és m között akárhányszor ismételheti
{n,} az atomot n és végtelen között akárhányszor ismételheti
{,m} az atomot 0 és m között akárhányszor ismételheti

Összefűzöttek

Az atomok és a lezártak egymás után írt sorozata.

A lezártaknál fontos kitétel volt, hogy csak atom után lehet írni. Egy összefűzött újra atomizálható a ( ) karakterekkel. Az összefűzöttek tartalmazhatnak uniót (|), ahol több szabály közül bármelyik megvalósulhat egy sikeres illesztéshez.

Parancsok és példák

Ez egy teszt szöveg, amin próbálkozunk.

A fenti szöveget alapul véve, a következő reguláris kifejezéseket hozhatjuk létre:

Reguláris kifejezés Illeszkedik? Magyarázat
E Igen Van a sorban E betű
a Igen Van a sorban a betű
b Nem Nincs a sorban b betű
^E Igen A sor elején van az E betű
^A Nem Nincs a sor elején A betű
^e Nem nincs a sor elején e betű
.$ Igen Bármilyen karakter lehet a sor végén
\. Igen . van a sor végén
k$ Nem Nincs k a sor végén
egy igen Van a sorban „egy” string
egység Nem Nincs a sorban egység string
egy* Igen eg kötelező, y 0 vagy végtelenszer lehet (egy, egyy, egyyy, egyyyy ...)
l*egy Igen l 0 vagy végtelen, eg kötelező (eg, leg, lleg, llleg, lllleg ...)
l+egy Nem Nincs a szövegben "l+egy" string
l\+egy Nem l 1 vagy végtelen hosszú, egy kötelező (legy, llegy, lllegy, llllegy ...)
(egy) Nem Nincs a sorban "(egy)" string
\(egy\) Igen Van a sorban "egy" string
\(egy\)* Igen Van a sorban legalább 0-szor "egy" string
\(egy\)\+ Igen Van a sorban legalább 1-szer "egy" string
\(egy\)\{2\} Nem Nincs a sorban pontosan kétszer "egy" string
[a-z] Igen Vannak benne kisbetűk
[A-Z] Igen Van benne nagy betű
^[A-D] Nem Nincs a sor elején A-D tartományban betű
^[A-Z] Igen Nagy betű van a sor elején
^[A-Z].*\.$ Igen Nagybetűvel kezdőik, középen bármi lehet és ponttal végződik a sor.
[0-9] Nem Nincs számjegy a sorban
.* Igen Mindenre illeszkedik, bármilyen hosszan (üres sorra is)
^$ Nem Csak az üres sorra illeszkedik
^.\+$ Igen Mindenre illeszkedik, kivéve az üres sorra

A következő kifejezés szintén illeszkedik:

^[A-Z].*\(egy\)\|\(kettő\).*\.$ => A sor elején nagybetűvel kezdődik, van a közepén valahol benne "egy" vagy "kettő" karakterlánc és ponttal végződik. A köztes karakterek értéke nincs megszabva.

grep

A grep utasítás segítségével végezhetünk el reguláris kifejezés, tehát minta illesztést fájlokon. Amennyiben nem adunk meg fájl paramétert, a STDIN csatornát olvassa. Az eredmények a STDOUT-ra íródnak.

Fontosabb kapcsolók
Rövid név Hosszú név Magyarázat
-c --count Megszámolja az illeszkedő sorokat
-o --only-matching Csak a mintára illeszkedő részt írja ki (nem a teljes sort)
-n --line-number Megszámozza a sorokat (a fájl alapján, nem a megjelenítés szerint)
Példa
# nologin környezetet futtató felhasználók listája a rendszerben
grep "nologin" /etc/passwd
cat /etc/passwd | grep "nologin" # STDIN-en érkező adatok szűrése

# bash környezetet futtató felhasználók listája a rendszerben
grep "bash" /etc/passwd
cat /etc/passwd | grep "bash"    # STDIN-en érkező adatok szűrése
Példa 2

Írjunk egy scriptet, amely a /bin/bash futtatási környezetet kapó felhasználók nevét kiírja a képernyőre.

#!/bin/bash

# a fájl, amin dolgozunk
file="/etc/passwd"
# a fájl sorainak száma
lines=`cat $file | wc -l`

# végig megyünk a fájl sorain
for i in `seq 1 $lines`; do
 # itt kapjuk meg az i. sort
 line=`head -$i $file | tail -1`
 # kiszedjük a shell környezetet
 shell=`echo $line | cut -f7 -d':'`
 # ha ez "/bin/bash", akkor kivágjuk a sor első oszlopát, ezt írhatjuk a képernyőre
 if test $shell == "/bin/bash"; then
  echo $line | cut -f1 -d':'
 fi
done
A fenti script futási ideje: 0.227s


#!/bin/bash
# a fájl, amin dolgozunk
file="/etc/passwd"
# szűrjük ki a sorokat, amelyeknek a végén a "/bin/bash" karakterlánc található 
#  és a kapott eredményhalmaznak vágjuk ki az első oszlopát
# a kapott eredményhalmaz még mindig megfelel a /etc/passwd eredeti formátumának, 
#  csak a sorok számát csökkentettük a szűrési feltételnek megfelelően!
grep "/bin/bash$" $file | cut -f1 -d':'
A fenti script futási ideje: 0.003s


MAC cím parser

Legyen egy MAC címeket tartalmazó fáljunk - mac-cimek.txt:

00:0C:42:AB:CD:EF
00:0c:42:ab:cd:ef
00-0C-42-AB-CD-EF
00-0c-42-ab-cd-ef
000c42abcdef
000C42ABCDEF
00:0C:42:AB:CD:EF:AB
00:0C:42:AB:CD:EF:
0G:0C:42:AB:CD:EF
00.0C.42.AB.CD.EF
00:0C:42:AB:CD:EG

Ebben a fájlban vannak megfelelő és hibás szintaktikájú címek is. A feladat, hogy készítsünk reguláris kifejezést, amely megjeleníti a helyeseket a képernyőn.

grep "^\([[:xdigit:]]\{2\}[-:]\?\)\{5\}[[:xdigit:]]\{2\}$" mac-cimek.txt
Érdekességképp beletehetünk a fájlba a MAC címek elé és/vagy után véletlenszerű (megjeleníthető) karaktereket.
Mit tapasztalunk? Miért?
Távolítsuk el a sor eleje és a sor vége illesztéseket és futtassuk a grep-et a -o kapcsolóval? Mi változik?
(grep -o "\([[:xdigit:]]\{2\}[-:]\?\)\{5\}[[:xdigit:]]\{2\}" mac-cimek.txt)

4. óra

A negyedik órán a reguláris kifejezések elkészítését gyakoroljuk különböző példákon keresztül. Főleg scripten belül használjuk.

5. óra

Az ötödik órán minta ZH feladatsort oldunk meg.