A bash egy unix rendszerhéj, amely a GNU Projekt részeként készült. A futtatható fájl neve bash egy játékos mozaikszó, mely a Bourne again illetve a born again kifejezéseket rövidíti. Ez a korai Bourne shell-re utal, melyet még 1978-ban adtak ki a Unix 7 Verzió részeként. A bash-t 9 évvel ezt követően 1987-ben készítette el Brian Fox, majd 1990-ben Chet Ramey vette át a szoftver gondozását.

Bash
Bash és Bourne-shell (sh)
Bash és Bourne-shell (sh)

Fejlesztő Chet Ramey
Első kiadás 1989. június 7.
Legfrissebb stabil kiadás 5.2.21 (stabil verzió, 2023. november 9., https://ftpmirror.gnu.org/bash/bash-5.2.21.tar.gz)[1]
Programozási nyelv C
Operációs rendszer multi-platform
Platform GNU
Kategória Unix shell
Licenc GNU General Public License
A Bash weboldala
Képernyőkép

A legtöbb Linux rendszeren, valamint az OS X rendszereken a bash az alapértelmezett shell. A Microsoft Windows platformra is átírták a Subsystem for UNIX-based Applications (SUA) használatával, vagy POSIX emuláció biztosításával a Cygwinnel, MSYS-szal.

A bash-t a GNU GPL licenc alatt publikálták, tehát szabad szoftver.

Inicializálás szerkesztés

A bash inicializálása attól függ, hogy milyen módban indítják.

Interaktív login mód szerkesztés

Ebben az esetben a /etc/profile script kerül először végrehajtásra, ha az létezik. Ezt követően a bash megvizsgálja a ~/.bash_profile, ~/.bash_login és a ~/.profile fájlokat ebben a sorrendben, s lefuttatja közülük az első olyat, amely létezik és olvasható.

Interaktív (nem login) mód szerkesztés

Ha a bash interaktív nem login shellként indul, akkor a felhasználó home könyvtárában lévő .bashrc fájlt futtatja, ha az létezik.

Nem interaktív mód szerkesztés

Ha a bash-t nem interaktívan futtatják, például shell script-ek végrehajtásához, akkor a BASH_ENV környezeti változóban megadott inicializáló script fog lefutni induláskor.

Restricted (szigorú) mód szerkesztés

Ha a bash -t az rbash binárissal, vagy a --restricted kapcsolóval indítják, ezen mód kerül érvényre. A következő funkciók letiltásra vagy korlátozott használatra állnak be:

  • Könyvtárak váltása a cd paranccsal
  • A következő környezeti változók értékeinek felülírása: SHELL, PATH, ENV, és BASH_ENV
  • Parancsok végrehajtása, melyek nevében slash "/" karakter szerepel
  • Fájlnév specifikálása amely slash karaktert tartalmaz a . beépített parancshoz
  • Fájlnév specifikálása amely slash karaktert tartalmaz a beépített hash parancs `-p' opciójához
  • Funkció definíciók importálása a shell környezetből indulás közben
  • A SHELLOPTS változó értékének értelmezése a shell környezetből indulás közben
  • Kimenetek átirányítása a `>', `>|', `<>', `>&', `&>', és a `>>' parancsokkal
  • A beépített exec parancs használata a shell cseréjére
  • Beépített parancsok hozzáadása vagy eltávolítása az `-f' és a `-d' opciókkal
  • A `-p' opció használata bármely beépített parancshoz
  • A szigorú mód kikapcsolása a `set +r' vagy `set +o restricted' parancsokkal

A szigorú módot sok felhasználót kiszolgáló, biztonságosra tervezett rendszerek esetén alkalmazzák.

Speciális karakterek szerkesztés

A parancssorba írt információk egy része az utasítást végrehajtó programnak szól, más részük a programot indító bash-nek. Az utóbbiakat speciális karakterekkel jelezzük.

Új sor szerkesztés

A legegyszerűbb speciális karakter a parancssort lezáró újsor (soremelés, LF). Hatására a bash

  1. befejezi a parancs beolvasását és elemzi a parancsot
  2. elindítja a parancsban megadott programo(ka)t
  3. megvárja, amíg az véget ér, és csak azután ad lehetőséget újabb parancs begépelésére (a prompt kiírása után).

A harmadik lépés elhagyható egy másik speciális karakterrel. A parancs után írt & arra utasítja a bash-t, hogy ne várja meg a parancs lefutását (háttérben indított program; lásd még job control). Miután az indított program örökli a szülő nyitott fájljait, és a bash is tovább fut, a két program kimenete összekeveredik (hacsak a gyerekprogram nem módosítja a kapott nyitott fájlokat).

Tipikusan egy sorban egy parancs van, de lehet folytatósort írni (egy parancs több sorban), és többféle módon lehet több parancs egy sorban.

Szóhatár szerkesztés

Az utasítás elemzésének egyik legutolsó lépése a szavakra bontás.[2] Az utasítás első szava a végrehajtandó parancs/program neve, a többi szót a program paraméterként kapja meg.

A szóhatárt az IFS nevű környezeti változó tartalmazza, értéke alaphelyzetben helyköz, tabulátor, új sor (LF).[3] Több egymás utáni szóhatár-karakter egy szóhatárnak számít. (Üres szót pl. "" alakban lehet írni, lásd speciális karakter elrejtése.)

Speciális karakter elrejtése szerkesztés

Sokszor van rá szükség, hogy a speciális karaktert a végrehajtandó parancs kapja meg, más szóval: a bash ne kezelje azt speciálisan. Ennek három módja van:

  1. a \ az őt követő egyetlen karaktert nem tekinti speciálisnak. A \-jel \\ alakban írható.
  2. ' (aposztróf): az összes speciális karaktert elrejti (kivéve a lezáró újabb '-ot)
  3. ": az összes speciális karaktert elrejti, kivéve
    1. \ (lásd feljebb)
    2. $ (hivatkozás környezeti változó vagy aritmetikai kifejezés értékére)
    3. ` (parancson belüli parancs végrehajtása; lásd backtick parancs)
    4. " (az elrejtés lezárása)

Az elrejtő karakterek felváltva is használhatók. Pl. a "' szöveg a bash számára írható '"'"'", \"\', "\"'" és számos más alakban.

Speciális eset a sor végi \újsor, mely a folytatósor jele: a bash eltávolítja a parancssorból, és a következő „fizikai” sorral folytatja a parancs belolvasását.

Wildcard szerkesztés

A wildcard olyan karakter, mely lehetővé teszi fájlnévminta megadását:

  • *: nulla vagy több karakter a fájlnévben
  • ?: egyetlen karakter a fájlnévben
  • [karakterek]: a szögletes zárójelben felsorolt karakterek valamelyike. A karakterek helyén intervallum is megadható. Pl. [a-z0-9-] a kisbetűket, számjegyeket és a kötőjelet jelenti.
  • [^karakterek] vagy [!karakterek]]: egyetlen, a szögletes zárójelben felsoroltaktól különböző karakter.

A bash megkeresi a wildcard-ot tartalmazó szóra illeszkedő nem rejtett fájlokat, és ezek listáját helyközzel elválasztva a parancssorba illeszti a wildcard-os szó helyére.[4] Ha nincs ilyen fájl, nem módosít a parancssoron.

A bash számára speciális (nem wildcard) karakter a szó (fájlnév) elején álló tilde (~), melyet a bash a felhasználó saját (HOME) könyvtárára helyettesít.

A bash számára a ponttal kezdődő nevű fájlok rejtettek: a wildcard kiterjesztésekor nem kerülnek a listába, kivéve, ha a wildcard-os fájlnév ponttal kezdődik. Minden könyvtárban van két rejtett fájl: a . az aktuális, a .. a felette levő könyvtár neve. Ezek szükségesek a könyvtárszerkezetbeli navigáláshoz.

A fentiekből következik, hogy a Unix-programoknak nem kell felkészülniük a wildcard kezelésére, hiszen ezeket a shell – e szócikkben a bash – elvégzi, ráadásul egységes módon.[5] Ehelyett tetszőleges számú fájlt kell tudniuk feldolgozni. A hívott program nem is tudja, hogy a fájl-paramétereit wildcard-dal vagy a fájlok felsorolásával kapta-e.

Példák wildcard-ra:

  • *: a könyvtár összes nem rejtett fájlja
  • *.*: legalább egy pontot tartalmazó fájlnév
  • *\ *: legalább egy helyközt tartalmazó fájlnév (a \ jelentését lásd feljebb)
  • [A-Z]*: nagybetűvel kezdődő fájlnév
  • *.c: .c kiterjesztésű fájlnév[6]

Környezeti változók szerkesztés

A kernel a processz (program) adatai között nyilvántart egy memóriaterületet, melyben név=érték típusú adatok vannak. Amikor egy program elindít egy másik programot,[7] az indított (gyerek)program örökli a szülő éppen aktuális környezeti változóit. A másik lehetőség, hogy a szülő állítja elő a gyerekprogram környezeti változóit, és egy memóriaterületen átadja a gyerekprocesszt indító rendszerhívásban.

A bash mindig az utóbbi módon indít programot. Ez lehetővé teszi, hogy egyes környezeti változói helyiek legyenek, mások az indított program környezetébe is bekerüljenek.

A bash indulásakor már vannak környezeti változói az őt indító programtól (pl. a bejelentkezési eljárásból), és a bash többféle indító scriptje is létrehoz változókat. A bash lehetővé teszi a változók lekérdezését, módosítását, törlését, újak létrehozását.

Fontos tudni, hogy Unixban minden program – a bash is – csak a saját környezeti változóit tudja megváltoztatni, a szülőjéét nem, ui. annak csak a másolatát kapja meg.

A bash környezeti változói az env utasítással, az indított programoknak továbbadottak a set utasítással listázhatók ki. A két listában a nevek és értékek is szerepelnek.

A környezeti változó értékét a $név vagy ${név} kifejezés adja meg. A két alak egyenrangú; a másodikat akkor használjuk, ha a változót el akarjuk választani az őt követő betűtől vagy számtól (ami az első alakban összeolvadna névvel). Az értékre hivatkozást általában idézőjelbe teszünk, bár ez nem mindig szükséges. Az értéket a echo "$név" utasítás írja a képernyőre. Nem hiba értéket nem kapott változót használni; ennek értéke üres string.

Új helyi változót létrehozni, vagy a meglevőt módosítani a név=érték utasítással lehet. Az egyenlőségjel előtt és után nem lehet helyköz. Az értékben szerepelhet a változó régi értéke.

Ha azt szeretnénk, hogy a változót az indított programok is lássák, az export név utasítást használjuk. A név után az érték is megadható.

Változó az unset név utasítással törölhető.

A legfontosabb környezeti változók szerkesztés

  • HOME: a bejelentkezett felhasználó saját könyvtára.
  • IFS: szóhatár.
  • PATH: könyvtárak kettősponttal elválasztott listája. Itt keresi a kernel az indítandó programot, ha annak útvonala nincs megadva. Az aktuális könyvtár a Dos/Windows rendszerektől eltérően alaphelyzetben nincs a PATH-ban, és biztonsági okból nem is tanácsos betenni, különösen a mindenható root felhasználó esetén.
  • PS1, PS2, PS3, PS4: a prompt szövegét megadó változók (normál prompt, folytatósor prompt, a select utasítás promtja, debug prompt).
  • SHELL: a shell neve; e szócikkben /bin/bash.[8]

Példák szerkesztés

A PATH kibővítése a felhasználó könyvtárának bin alkönyvtárával:

export PATH=$PATH:$HOME/bin

Ugyanez leírható

export PATH+=:$HOME/bin

alakban is.

Átirányítás szerkesztés

Amikor Unixban egy program elindít egy másikat, a gyerekprogram – a környezeten kívül – a nyitott fájlokat is örökli. A felhasználó bejelentkezési procedúrája során több program is lefut, és ennek során létrejön három nyitott fájl azon az eszközön (terminálon, soros vonalon, stb.), ahonnan a felhasználó bejelentkezett, így a felhasználó login shellje ezeket már megnyitva kapja. A fájlok a megnyitás sorrendjében kapnak számot a kerneltől:

  • 0: standard input
  • 1: standard output
  • 2: standard hiba.

Az átirányítás célja a, hogy az indított program ne a bash-től örökölje a fenti fájlokat, hanem a parancssorban megadott fájlokat kapja meg. A három fájl egymástól függetlenül irányítható át.

A standard input átirányítása szerkesztés

Az egyik mód az indított program standard inputjának megadása:

program <fájl

A másik mód shell scriptben használatos: az indított program az indító scriptből vegye a standard inputot:

program <<szó
program stdin-jének első sora
második sor
...
szó

A „fájlt” lezáró szó a sor elején kell legyen. Ha a hívott program végigolvassa az standard inputját, a záró szó helyett fájl végét kap. Ha nem olvassa végig, a következő utasítás előtt a bash átugorja a be nem olvasott részt.

A kimenetek átirányítása szerkesztés

A standard kimenet átirányítása:

program  >fájl
program >>fájl

Mindkét alak létrehozza fájl-t, ha az nem létezett a parancs kiadásakor. Az első a létező fájl tartalmát törli, de a jogait nem változtatja. A második a fájl vége után írja program kimenetét.

Fontos tudni, hogy az átirányítás a program indítása előtt történik (lásd alább). Az első alakban fájl tartalma akkor is megsemmisül, ha a hívott program nem is létezik.

A standard hiba átirányítása teljesen hasonló:

program  2>fájl
program 2>>fájl

A bash standard kimenetére &1, a hibakimenetre &2 alakban hivatkozhatunk.[9]

Egy program mindkét kimenete ugyanabba fájlba irányítható:

program >fájl 2>&1

Egy program indítása két lépésben történik. Első lépés a fork, melynek során az indító bash teljes memóriája és processztáblája megduplázódik, azaz a bash két külön környezetben (szülő és gyerek) fut tovább. A második lépés a program kódjának betöltése a gyerek-bash helyére, és az újonnan betöltött kód elindítása.

Az átirányítás a fork fázisban történik, hogy a bash eredeti környezete ne változzék.[10] A fenti példában a >fájl fájl újranyitás az 1-es számú fájlleírón, vagyis egy rendszerhívás, mely bezárja az eredeti fájlt, és a helyére megnyit egy másikat. A 2>&1 az 1-es fájlleíró duplikálása a 2-es leíróba. Ez azt is jelenti, hogy a fenti sorrend nem felcserélhető. A 2>&1 >fájl az eredeti fájlleírót duplikálja, így az újranyitás már nem hat a hibakimenetre.

A fenti kettős átirányítás egy utasítással is végrehajtható:

program &>fájl

Gyakran használatos a kimenet átirányítására a /dev/null speciális eszközfájl, mely „elnyeli” – eldobja – az oda küldött adatokat.

Parancsok kombinálása szerkesztés

Pipe szerkesztés

prog1 | prog2

hatására prog1 és prog2 között névtelen pipe jön létre.[11] A két program külön-külön processzként indul el úgy, hogy prog1 standard kimenete átirányítódik prog2 standard bemenetére. A bash megvárja mindkét program lefutását, és prog2 visszatérési értékét teszi a $? változóba. Kettőnél több program is összeköthető pipe-pal.

Backtick szerkesztés

Alakja:

parancs1 ... `parancs2...` ...
parancs1 ... $(parancs2...) ...

Először parancs2 hajtódik végre, és a standard kimenete behelyettesítődik parancs1 parancssorába (a paraméterek közé). Az újsor[12] karakterek helyközre cserélődnek.

A fenti két alak annyiban különbözik egymástól, hogy a backtick-ek nem skatulyázhatók egymásba, a $(...)-k igen.

Példa:

file `which ls`

A which ls parancs végigkeresi a PATH környezeti változót, és visszaadja az ls parancs fájljának útvonalát. A file parancs kiírja a parancs típusát:

$ file `which ls`
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), ...

; szerkesztés

A pontosvesszővel elválasztott parancsok egymás után futnak le. Az utolsó parancs visszatérési értéke kerül a $? változóba.

Példa: fájlt másolunk egy másik ablakban, és közben figyeljük a diszk telítettségét:

while true ; do df -hT ; sleep 30 ; done

&& szerkesztés

A && bal oldalán levő parancs lefutása után akkor hajtódik végre a jobb oldali, ha a bal sikeres volt (a visszatérési értéke 0).

Példa: a make paranccsal lefordítjuk a prog programot, és ha a fordítás sikerült, végrehajtjuk:

make && ./prog

|| szerkesztés

A jobb oldali parancs akkor hajtódik végre, ha a bal oldali sikertelen volt (nem 0 a visszatérési értéke):

make || exit 2

Kerek zárójel szerkesztés

A kerek zárójelbe tett parancsok egy shellben futnak le. Ez pl. akkor lehet hasznos, ha egy fájlba akarjuk irányítani a kimenetüket, vagy egy processzben akarjuk őket futtatni háttérben. A zárójelet helyközzel kell elválasztani a parancs többi részétől.[13] A parancsok több sorba is írhatók.

Shell script szerkesztés

A script (egyre gyakrabban írják magyarosan szkriptnek) Unixban olyan fájl, mely egy interpretált programozási nyelv utasításait tartalmazza. Interpreterek a Unix shellek – köztük a bash – is.

Script hívása szerkesztés

A bash a shell scriptet ugyanúgy indítja el, mint a bináris programokat. Ez azt jelenti, hogy a script másik shellben fog futni.[14] Ez általában kényelmes, viszont a hívott shell nem tudja megváltoztatni a hívó környezetét (így a környezeti változókat sem). Ennek megoldására szolgál a pont parancs:

. shell-script
source shell-script

A két alak egyenértékű, és a script neve után paraméterek is megadhatók. A parancs hatására a bash nem indít külön programot, hanem ő maga hajtja végre a megadott shell scriptet.

A hívott script (vagy más program) visszatérési értéke a $? shell-változóba kerül. A hívott script az exit utasítás paraméterében állíthatja be a visszaadandó értéket.

Az első sor szerkesztés

A program indításakor a kernel[7] „belenéz” az indítandó fájl elejébe, és ebből állapítja meg az indítás módját.[15] Script esetén a fájl a #!interpreter sorral kezdődik.[16] Az interpreter nevét az új sor (LF) karakter zárja le. (Ügyeljünk rá, hogy ne legyen előtte CR, mert az is a név része lenne.) A kernel az interpretert indítja el, első paraméterként átadja a scriptfájlt. Az interpreter a többi paraméterét a hívósorból kapja, hogy átadhassa a scriptnek.

A bash-script első sora Linuxban:[8]

#!/bin/bash

A scripteket a /bin/sh sorral szokás kezdeni, ami a Bourne shellt hívja.[17] A bash a Bourne shell továbbfejlesztett változata; ha szükség van a többlet-utasításokra (pl. tömbökre), akkor az előbbi formát kell használni.

Paraméterek szerkesztés

A script a saját fájlnevét (útvonallal együtt) a $0 változóban kapja, a többit a $1...$9 változóban. Tíznél több paraméter a beépített shift utasítással vehető át. A kapott paraméterek számát a $# változó tartalmazza.

Scriptnyelv szerkesztés

Bár a shell elsősorban külső programok hívására szolgál, saját beépített utasításai is vannak, melyek önálló programnyelvet alkotnak. A harmadik generációs programnyelvek[18] szokásos utasításaira példák:

Bash függvények szerkesztés

Bash-függvény definiálása:

fuggveny()
{
...
}

Hívás: fuggveny par1 par2.... Függvényen belül a $1...$9 változó nem a shell script, hanem a függvény paraméterét jelenti. A függvény a return kód utasítással adhat vissza számértéket.

Aritmetikai kifejezések szerkesztés

Egész aritmetikai kifejezés $(( ... )) alakban írható. A műveletek azonosak a C nyelvbeliekkel. Az operandusok környezeti változók is lehetnek.

Példa:

HAROM=$((1+2))

Háttérben indított programok szerkesztés

Program háttérben indításakor kiíródik a processz száma, melyet a script változóba tud tenni. A script a wait procszám utasítással várhatja meg a program lefutását. A paraméter nélküli wait az összes háttérbeli programot megvárja.

Job control szerkesztés

A jobs utasítás kilistázza a shellből indított, még le nem futott programokat, akár eleve háttérben indítottuk őket, akár utólag, kézzel állítottuk meg és/vagy tettük háttérbe (lásd alább). A program akkor minősül „lefutott”-nak, ha befejeződött a végrehajtása, és ezután lekérdezték a státusát.[19] A lekérdezést elvégzi a jobs, de maga a bash is, mielőtt kiírja a következő utasítás promptját.

Mialatt a bash az indított program lefutására vár, a Ctrl/Z megszakítja a várakozást (SIGTSTP szignál), megállítja az indított programot, és visszaadja a promptot. A bg szám háttérben, a fg szám előtérben indítja tovább a programot, ahol szám a jobs által kiírt job sorszám.

A Ctrl/C (SIGINT szignál) befejezi az előtérben futó programot. Ha a bash fut, Ctrl/C-re eldobja az addig beolvasott sort, és új promptot ír ki.

Szignálok szerkesztés

A szignál segítségével az egyik Unix processz értesítheti a másikat egy esemény bekövetkeztéről. 64-féle szignál van, melyek különböző eseményeket jelezhetnek. Ha a programot nem úgy írták meg, hogy képes legyen szignált fogadni, a szignáltól függő default akció történik a szignál címzettjével:

  • befejeződik a futása
  • figyelmen kívül marad a szignál
  • a processzről core dump készül
  • a processz futása megáll
  • a processz futása újraindul.

A SIGKILL (9-es) szignál nem jut el a címzetthez: a kernel kilövi a címzett processzt (feltéve, hogy a küldőnek erre volt joga). Ha egy program elszabadul, és már szignálokra sem reagál, ez az egyetlen módja a program leállításának. Hátránya, hogy a program nem tud rendet tenni a befejeződése előtt (pl. a puffereit kiüríteni).

bash-ban a kill -l beépített parancs kilistázza a szignálok nevét és kódját.

Szignál küldése bash-ből szerkesztés

Szignál küldése:

kill -szám procid...

ahol szám a szignál száma vagy neve (ha elmarad, 2 = SIGTERM), melyet processzazonosítók helyközzel elválasztott listája követ. A név arra utal, hogy legtöbb esetben programok kilövésére használjuk a parancsot. A létező processzazonosítókat pl. a ps és pgrep parancs írja ki.

A killall és pkill parancs lehetővé teszi szignál küldését adott nevű és/vagy adott felhasználóhoz tartozó processzeknek.

Shell script a trap utasítással fogadhat szignálokat.

Jegyzetek szerkesztés

  1. bash-5.2.21.tar.gz, 2023. november 9. (Hozzáférés: 2023. november 9.)
  2. A parancssor utasításokra bontása korábbi lépésekben történik.
  3. Így lehet kiíratni: echo -n "$IFS" | hexdump -C
  4. A bash parancssorának hossza a kerneltől függ, alaphelyzetben 128 kByte.
  5. Néhány speciális program, pl. az ls és a find saját fájlkeresést használ.
  6. Unixban nincs fájl kiterjesztés: e szó a DOS-os terminológiából származik. A pont nem különleges karakter a fájlnévben.
  7. a b Lásd exec rendszerhívás-családot.
  8. a b Egyes Unixokban a bash a /usr/bin könyvtárban van.
  9. Ha a bash-ben további fájlokat nyitottunk meg, azok fájlszáma is írható ilyen alakban.
  10. A fork fázis célja éppen az indítandó program környezetének beállítása a szülő memóriaterületén levő adatokból.
  11. Névvel rendelkező pipe a mkfifo paranccsal hozható létre.
  12. Pontosabban: az IFS környezeti változó karakterei.
  13. A helyköz nélküli listát egy tömb elemeinek tekinti a bash.
  14. A Dos/windowsos rendszerekben ez éppen fordítva van. A shell a kiterjesztésből tudja, hogy shell scriptet kell hívnia, és azt ugyanazzal a shellel hajtja végre, hacsak nem használjuk a call beépített utasítást.
  15. A file paranccsal kiíratható az információ.
  16. Ez azt jelenti, hogy a script-nyelvek a #-sel kezdődő sorokat – legalábbis az első sorét – kommentnek kell tekintsék.
  17. Linuxban a Bourne shellt is a bash hajtja végre szűkített módban futva.
  18. Lásd programnyelv-generációk(en).
  19. Ha a program lefutott, de a szülő még nem kérdezte le a státusát, a program a memóriában marad. Az ilyen processzt nevezik zombinak(en).

Források szerkesztés

További információk szerkesztés

Kapcsolódó lapok szerkesztés