bash
A bash 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) | |
Fejlesztő | Chet Ramey |
Első kiadás | 1989. június 7. |
Legfrissebb stabil kiadás | 5.2.37 (stabil verzió, 2024. szeptember 23.)[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 |
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ésA bash inicializálása attól függ, hogy milyen módban indítják.
Interaktív login mód
szerkesztésEbben 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ésHa 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ésHa 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ésHa 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ésA 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ésA legegyszerűbb speciális karakter a parancssort lezáró újsor (soremelés, LF). Hatására a bash
- befejezi a parancs beolvasását és elemzi a parancsot
- elindítja a parancsban megadott programo(ka)t
- 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ésAz 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ésSokszor 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:
- a
\
az őt követő egyetlen karaktert nem tekinti speciálisnak. A \-jel\\
alakban írható. '
(aposztróf): az összes speciális karaktert elrejti (kivéve a lezáró újabb '-ot)-
"
: az összes speciális karaktert elrejti, kivéve\
(lásd feljebb)$
(hivatkozás környezeti változó vagy aritmetikai kifejezés értékére)`
(parancson belüli parancs végrehajtása; lásd backtick parancs)- " (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ésA 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:
Környezeti változók
szerkesztésA 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ésA 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ésAmikor 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ésAz 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ésA 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ésPipe
szerkesztésprog1 | 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ésAlakja:
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), ...
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ésA && 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ésA 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ésA 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ésA 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ésA 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ésA 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ésA 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ésBá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:
- deklaráció: export.
- értékadás: lásd környezeti változók, aritmetikai kifejezések
- vezérlő utasítások: if, case, for, while, until, test
- I/O utasítások: cd, pwd, echo, printf, read
- függvények
- processzek: lásd job control, szignálok.
Bash függvények
szerkesztésBash-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ésEgé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ésProgram 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ésA 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ésA 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ésSzigná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- ↑ https://ftp.gnu.org/gnu/bash/
- ↑ A parancssor utasításokra bontása korábbi lépésekben történik.
- ↑ Így lehet kiíratni:
echo -n "$IFS" | hexdump -C
- ↑ A bash parancssorának hossza a kerneltől függ, alaphelyzetben 128 kByte.
- ↑ Néhány speciális program, pl. az ls és a find saját fájlkeresést használ.
- ↑ 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.
- ↑ a b Lásd exec rendszerhívás-családot.
- ↑ a b Egyes Unixokban a bash a /usr/bin könyvtárban van.
- ↑ Ha a bash-ben további fájlokat nyitottunk meg, azok fájlszáma is írható ilyen alakban.
- ↑ 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.
- ↑ Névvel rendelkező pipe a
mkfifo
paranccsal hozható létre. - ↑ Pontosabban: az IFS környezeti változó karakterei.
- ↑ A helyköz nélküli listát egy tömb elemeinek tekinti a bash.
- ↑ 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.
- ↑ A file paranccsal kiíratható az információ.
- ↑ Ez azt jelenti, hogy a script-nyelvek a
#
-sel kezdődő sorokat – legalábbis az első sorét – kommentnek kell tekintsék. - ↑ Linuxban a Bourne shellt is a bash hajtja végre szűkített módban futva.
- ↑ Lásd programnyelv-generációk(en).
- ↑ 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- Bash Reference Manual (gnu.org)