HIBAKERESÉS, TIPPEK ÉS TRÜKKÖK
Ebben a fejezetben gyűjtöttük össze, lehetőleg témák szerint rendezve, mindazokat a problémákat, amelyek a kezdő Unix felhasználó életét oly gyakran megkeserítik. Az elhangzottak egy részére a könyvben már szerepeltek utalások, mások a sehova be nem illeszthető, "mit tegyünk ha..." kategóriába tartoznak. Szerepelnek itt olyan problémák, amiket a tanfolyamaink hallgatóinál tapasztaltunk, mások viszonylag közismert és gyakran előforduló gondok, melyekre ugyan ott szerepelnek a kézikönyvekben a megoldások és bölcs intenciók, de ezekre a legritkább esetben bukkanhatunk rá céltudatos kereséssel... Mindegy, íme egy csokor az általunk legfontosabbaknak ítéltekből; csak buzdítani tudunk mindenkit e lista saját bővítésére, s ha ezt megosztják velünk a könyv következő kiadására, hisszük, hogy ez mindenki számára hasznos és gyümölcsöző lesz.
Bejelentkezés, terminálkezelés
Problémánk gyökere valószínűleg abban rejlik, hogy bejelentkezési nevünk csak nagybetűket tartalmaz (vagy véletlenül a CapsLock gombot lenyomtuk); a login program, amelyik a bejelentkezéseket ellenőrzi, ezek után azt tételezi fel, hogy olyan terminálon dolgozunk, amelyik csak a nagybetűket ismeri (ó, a hőskor...!) - s a továbbiakban ehhez is tartja magát, mindent nagybetűvel ír, a tényleges nagybetűket rendszerint egy eléjük helyezett backslash karakterrel különbözteti meg.
Az egyik megoldás, ha a CapsLock "beragadása" okozta a problémát, a kijelentkezés, és újbóli belépés; ha a ellenben a bejelentkezési nevünk van rosszul megválasztva, cseréltessük le a rendszergazdával úgy, hogy legalább egy kisbetűt is tartalmazzon, ettől a login program "észreveszi magát".
Ha valamilyen okból mégsem akarunk kilépni, az stty parancs megfelelő opcióival próbálkozhatunk: az
stty iuclc -olcuc -xcase
opciókombináció rendszerint segít a problémán.
Ha a rossz karakterek rendszeresen, minden második, harmadik karakterhelyen fordulnak elő, valószínűleg a paritáskezelés van rosszul beállítva. Az stty konfigurálását ilyenkor célszerű a rendszergazdára bízni, ha mégis magunknak kell boldogulni, akkor a parenb parodd cstopb cs7 cs8 paraméterekkel való szisztematikus kísérletezéssel állítsuk be a vonali jellemzőket.
Ha a hiba ékezetes magyar szöveg megjelenítésekor jelentkezik, valószínűleg az a gond, hogy terminálunk hét bites üzemmódra van állítva. Adjuk ki az
stty cs8 -istrip
parancsot a nyolcbites üzemmód beállítására.
Fájlkezelés, parancsbegépelés
A gond abban rejlik, hogy a '-' karaktert a programok opciókezdő karakternek tekintik, s ebbéli meggyőződésükről elég nehéz lebeszélni őket. Mindazonáltal több módon is megoldható a probléma. A legegyszerűbb, hogy a szóban forgó fájlnevet tetszőleges, akár relatív, akár abszolút elérési út megadással nevezzük meg, a lényeg az, hogy ne a mínusz jel kezdje a nevét. Ha például -xfile a fájl neve, a ./-xfile hivatkozás tökéletesen megoldja a problémát és "kezelhetővé" teszi a fájlt.
A másik megoldás, amit számos segédprogram elfogad, a '--' opció használata. Ez az opció ugyanis azt jelenti az adott programnak, hogy a következő paraméterek már nem tartalmaznak opciót. Így a fenti félresikerült nevű fájlt a legtöbb program jól kezeli a -- -xfile megadással. (Csak a zűrzavar fokozására említjük meg, egyes programok, például az rm egyes régebbi implementációi, az egyetlen mínusz jelet is ilyen értelemben kezelik, nem a standard bemenet vagy kimenet jeleként...)
A legkézenfekvőbb megoldás, hogy keresünk a fájlnévben egy olyan jellemző részt, amelyik ezt és csakis ezt a fájlt jellemzi, majd ezt a mintát a fájlnév behelyettesítési mechanizmus speciális karaktereit felhasználva adjuk meg törlésre, valahogy így:
rm *
egyedi_minta*Ha pontosan nem tudjuk, a speciális karakter hol is került bele a fájlnévbe (és általában nem is tudjuk, hiszen ezek egyben rendszerint nem-nyomtatható karakterek is), akkor az
od -c .
paranccsal kérjünk egy listát a munkakatalógusról. E listában a katalógusfájl tartalma karakteres formában jelenik meg, a nem nyomtatható karaktereket oktális formában adja meg. A lista alapján egyértelműen eldönthető, hogyan is néz ki valójában a keresendő fájlnevünk, s hogyan tudjuk elkerülni, hogy az egyedi_minta megadásába bekerüljön a galibát okozó karakter is.
Ha valamilyen oknál fogva a mintaillesztést nem használhatjuk, a fájlkezelő parancsok -i (interaktív) opcióját használhatjuk, melynek hatására egyenként visszaigazolást kér, hogy végrehajtsa-e a szóbanforgó fájlok a kérdéses műveletet.
Ha a -i opcióval se boldogulunk, derítsük ki a renitens állomány inode számát (például az
ls -il
paranccsal), majd egy célzott find paranccsal, amelyik a kapott inode-hoz tartozó fájlt keresi, töröljük illetve módosítsuk:
find . -inum
inode_number -ok rm -f {} \;(A fenti műveletsor végrehajtásakor ne felejtkezzünk el arról, hogy az inode-ok csak egy önálló (becsatolható) állományrendszeren belül egyediek, tehát mivel az egész állományrendszerben több azonos inode is lehet, vigyázni kell arra, vajon tényleg a kívánt állományt töröljük-e – e célból is célszerűbb a –ok opció használata a -exec ellenében.)
A lakonikus válasz az, hogy sehogy, s ez alól bizony kevés kivétel akad. Ha a problémán egy törlés után kezdünk el gondolkodni, bizony késő a bánat; a kitörölt fájlok felszabaduló blokkjai az állományrendszer szabad blokkjainak listájára fűződnek fel, ráadásul olyan szerencsétlen módon, hogy minden új helyfoglalási igénykor a legutoljára felkerült blokkokat osztja ki elsőként a rendszer. Egyetlen, hajszálnál is vékonyabb esély csak akkor van, ha akad a közelben szakértő rendszergazda aki azon nyomban lekapcsolja a gépet, majd többé-kevésbé manuális eszközökkel "visszavadássza" a törölt fájlt. A dolog közel sem triviális, s a sikere még ekkor is igen kétséges.
Egyetlen megoldás a megelőzés. Viszonylag könnyű és általános megoldást jelent az aliasok használata (sajnos ezt a mechanizmust nem minden shell ismeri). Ha viszont rendszerünkben használható, akkor az rm parancsot aliasként definiálhatjuk, az
alias rm 'rm -i'
vagy hasonló formában, s a továbbiakban az rm parancs meghívásakor az interaktív opció hatására rákérdez, hogy tényleg törölni akarunk-e. A megoldás (és minden más megoldás) hátránya a széles értelemben vett átvihetőség és szabványosság hiánya: ha egy másik Unixos gép elé ülünk le, nem biztos, hogy akár ez, akár más megoldás működik a gépen, s tévedésünkre rendszerint itt is csak az első törlés után döbbenünk rá...
'Command not found' vagy hasonló hibaüzenetet kapunk a shellscriptünk indításakor, noha végrehajthatóvá van téve és a munkakatalógusunkban van.
Néha, ha új környezetben dolgozunk, azt tapasztaljuk, hogy az elindított program nem indul el, pedig a munkakatalógusunkban van, és még végrehajtási jogunk is van rá. Ekkor jusson eszünkbe, hogy a Unix csak azokat a katalógusokat tudja elérni, amelyek a PATH változóban szerepelnek. Így ha az adott környezet PATH változójából hiányzik a mindenkori munkakatalógus, a prog nevű programot a ./prog paranccsal tudjuk elindítani. (A kurrens katalógus PATH változóba illesztését biztonsági okokból nem javasoljuk.)
Állítsuk be .cshrc fájlunkban az alábbiakat (a számérték természetesen egyéni ízlés dolga, a túl kis értékek az eseménypuffer értelmét kérdőjelezik meg, a nagy puffer pedig a shell indulását lassítja jelentősen):
set history=20
# eseménypuffer méreteset savehist=20
# a kilépéskor megõrzendõ puffer méreteVáltozó értékadásánál a 'var: not found' hibaüzenetet kapjuk.
A probléma oka minden valószínűség szerint az, (a standard Bourne és a Korn shell használatát feltételezve), hogy az értékadás '=' karakterét szóközök veszik körül. A shell ugyanis csak akkor ismeri fel, hogy értékadásról van szó, ha az első szón belül szerepel az egyenlőségjel; ha szóköz van az egyenlőségjel körül, a shell a változónevet fogja a végrehajtandó parancs nevének tekinteni, az egyenlőségjelet az első, a változóértéket pedig a második paraméternek. E probléma a C shellnél nem merül fel, ott a szóközök megléte vagy nemléte érdektelen.
A shellscript, amit futtatunk, meg kellene hogy változtassa a kurrens
katalógust (shellváltozót), de ez mégsem történik meg, a shellscript
lefutása után változatlan marad.
A magyarázat a Unix többfeladatos működéséből következik. Amikor egy shellscriptet elindítunk, a shell egy újabb, úgynevezett subshellben indítja el a scriptet. A subshell örökli szülője környezetét, annak egy másolatával dolgozik tovább, de ebből az is következik, hogy a shellscript lefutása és a subshell befejeződése semmilyen hatást nem gyakorolhat az eredeti shellváltozókra, hiszen azoktól teljesen függetlenül kezelte őket a rendszer.
A problémának ha nem is megoldását, de megkerülését úgy érhetjük el, hogy a futtatandó scriptet nem subshellel futtatjuk, s így a script által módosított változók a kurrens környezetet módosítják. Bourne és Korn shell esetén a
.
shellscriptparanccsal, míg C shell esetén a
source
shellscriptparanccsal lehet a kurrens shellben futtatni.
Ha a fájl az egyszerűség kedvéért .logout névre hallgat, akkor a
trap ". .logout" 0
parancs hatására, amikor a login shell a kilépést jelző 0 szignált észleli, végrehajtja a trap parancsban definiált parancsot, azaz a .logout fájlban megadott parancsokat.
Segédprogramok furcsaságai
A find parancs a -exec vagy -ok opció használatakor az 'incomplete statement' hibaüzenettel reagál.
Gyakran kapjuk ezt a hibaüzenetet, ha a find parancsot a -exec vagy -ok opciókkal hívtuk meg. A kézikönyv ugyan megemlíti, hogy az ezen opciók után beírandó parancsokat a '\;' karakterekkel kell lezárni, de azt nem, hogy e karakterek és a velük lezárt parancs között legalább egy szóközt is el kell helyezni... Tehát például a
find . -name thisfile -exec ls -l {}\;
megadás helytelen, helyette az alábbit kell használni:
find . -name thisfile -exec ls -l {} \;
(A probléma nem minden find implementációban fordul elő.)
Gyakran lehet gondunk a test beépített shell parancs rövidített írásmódjával, amikor e shell szerkezetet a [] jelekkel rövidítjük. Noha implementációnként eltérhet a shell reagálása, saját keserű tapasztalataink alapján forrón javasoljuk mindenkinek, hogy a szögletes zárójelek mindkét oldalán helyezzen el szóközöket. Az alább következő példa az esetek többségében szintaktikai hibához vezet:
if [-d $dfile];
...
helyesen (pontosabban biztonságosabban) így írjuk:
if [ -d $dfile ] ;
Az alábbiak inkább shellscriptek írása közben zavarnak, de a megfelelő tanulság interaktiv parancsírásra is levonható. A C nyelvhez szokott felhasználók a shell vezérlő utasításait gyakran írják egysorba, elválasztó pontosvessző nélkül, valahogy például így:
if date|grep SEPT then echo "Iskolaba megyunk" else echo "szunet van" fi
Biztosak lehetünk benne, hogy a fenti paranccsal jól megzavarjuk a shellt. Ugyanis, amit mi kulcsszónak gondolunk, azt a shell csak adott pozíciókban tekinti kulcsszónak, más helyen csak egy karaktersorozat, amit parancsargumentumként kezel. A kiemelt helyek, ahol a shell kulcsszókat keres: a soreleje, valamint a parancselválasztó pontosvessző utáni pozíció. Tehát a fenti parancs egy helyes alakja:
if date | grep SEPT; then echo "Iskolaba megyunk"
else echo "szunet van"; fi
Az általános ökölszabály az, hogy a then, és a do "töltelékszavak" vonhatóak össze egy sorba az őket megelőző if, for vagy while szintaktikus elemekkel. Az összevonás feltétele, mint a fenti példán láttuk, a pontosvessző használata, mert ez parancsszeparátorként a kiváltott újsor karaktert helyettesíti. Tehát például az
if
expr; thenwhile
expr; dofor
var in wordlist; dorövidítések biztonsággal használhatóak.
Milyen mintát kell adnunk a grep parancsnak ha egy állományból olyan sorokat szeretnénk kiválasztani,amelyek nem tartalmaznak egy adott karaktert, mondjuk a 9-es számot? Ez a kérdés minden alkalommal megizzasztja a hall-
gatókat. Ugyan is, ha olyan sorokat akarunk kiválasztani, amelyekben van 9-es szám, a dolgunk egyszerű, a minta maga a szám. Ha ennek negáltját adjuk meg mintának, ([^9]), az meg fogja találni az összes olyan sort, amiben van legalább egyetlen nem 9-es karakter. A helyes megoldás szavakban így fogalmazódik meg; keressük azt a sort, amelyben az elsőtől az utolsó karakterig nincs 9-es. Jelekben:
grep '^[^9]*$' file(s)
A vi (ed, ex) editor használata közben leállt a rendszer és elveszett az éppen szerkesztett fájl.
A vi egy külön könyvtárban biztonsági másolatokat tart fenn a szerkesztés menetéről. Rendszerhiba esetén a vi -r opcióval tudjuk megismételtetni a teljes előző szerkesztési menetet. A visszajátszás befejeztekor mentsük el a fájlt valamilyen néven, s máris továbbdolgozhatunk, nagy valószínűséggel csak az utolsó pár karakter hiányzik munkánkból.
Gyakoribb hibaüzenetek
Az alábbiakban a leggyakrabban előforduló hibaüzenetekből "mazsolázunk", a lehetséges gyakoribb kiváltó okokra rámutatva. Válogatásunk többé-kevésbé önkényes, hiszen alapvetően csak a minden rendszerben felbukkanó közös hibaüzenetekkel van értelme itt foglalkozni.
Túlságosan sok, vagy túlságosan kevés argumentumot adtunk meg a program által várthoz képest. Az adott program manuál oldalain nézzük meg a pontos szintaxist, de gyakran a parancs által kiírt online 'Usage:' ismertető is kisegít.
A meghívott programnak átadott argumentumlista túl hosszú. Rendszerint nem az általunk begépelt argumentumok okoznak túlcsordulást, hanem a parancssorban szereplő fájlbehelyettesítések (egy nagy könyvtárban kiadott * fájlnév stb) (a `...` parancsbehelyettesítési mechanizmus is szolgálhat hosszú argumentumlistákkal).
A pipeline-ba szervezett parancsok közül valamelyik időnek előtte elhalt, mialatt valaki még adatokat küldött neki.
A futtatott program már létező fájlt akar felülírni.
A program nem találja az általa keresett fájlt. A find paranccsal nézhetünk utána, ténylegesen hol is találhatóak a keresett fájlok.
A fájl kimerítette a rendelkezésre álló mérethatárt. (Az érték rendszerenként változhat.) Ilyen esetben forduljunk a rendszergazdához, mert számos esetben viszonylag könnyen lehet emelni a felhasználó számára rendelkezésre álló határokat.
A katalógusfájlt úgy próbáltuk meg írni/olvasni, mintha közönséges fájl volna.
A megadott fájlnév paramétert (akár katalógust, akár közönséges fájlt) nem találja a shell. Ellenőrizzük a megadott fájl- illetve katalógusnevet.
Katalógusnevet váró programnak nem katalógusnevet adtunk meg (például cd).
Olyan fájlt próbáltunk meg elérni vagy módosítani, amelyikre nincs meg a megfelelő jogunk. Ugyanezt a jelzést kapjuk, ha nem általunk indított folyamatot próbálunk meg törölni a kill paranccsal.
Túlságosan sok folyamat fut és elfogyasztották a rendelkezésre álló memóriát. A más által indított folyamatokkal persze nem sokat kezdhetünk, de a ps paranccsal megkereshetjük esetleges saját, már nem szükséges processzeinket, s törölhetjük őket. (Gyakran előfordul, hogy egy folyamat számos más folyamatot indít el, s ezek időnként "bentragadnak" a rendszerben, noha már nem futnak. (Kiváltképpen az X Window alapú, grafikus ablakfelülettel ellátott rendszereken szaporodnak minden mértéken felül.)
Megfelelő jogok hiányában próbáltuk meg olvasni, írni vagy végrehajtani a fájlt.
Túlságosan sok, vagy túlságosan kevés argumentumot adtunk meg a hívott programnak. (Például egynél több argumentum a cd parancsnál, vagy kettőnél kevesebb az mv-nél stb.)
Számos program, ha rossz argumentumokkal hívták meg, kiír egy rövid emlékeztetőt, hogy hogyan is kell helyesen használni. Ha e tájékoztató által nyújtott információ nem elég, akár az online, akár a nyomtatott kézikönyv ad részletesebb információt.
A programnak átadott opció ismeretlen a program számára.
Rendszerállapot változásai
Betelt a számunkra kijelölt kvóta, miközben új fájlt akartunk létrehozni, illetve már meglévőt módosítani. A kvótaértéket csak privilégizált felhasználó módosíthatja.
A fájlrendszer, amin írni próbáltunk, írásvédett. Önmagában álló, hálózatos kapcsolatok nélküli rendszeren ez rendszerint akkor fordul elő, ha a CD-ROM-ot, vagy az írásvédett floppyt az írásvédettség deklarálása nélkül próbáltuk a mount paranccsal becsatolni. Hálózaton lévő Unix rendszereknél gyakori, hogy a hálózaton keresztül, az NFS protokollal hozzáférhető fájlrendszerek is csak olvashatónak vannak deklarálva.
A megnevezett fájlrendszeren nincs több szabad hely. Noha ez általában több felhasználó szerencsés együttműködésének "gyümölcse", az esetlegesen általunk indított nagyméretű nyomtatási feladatok, "szemét" (junk) fájlok, átmeneti anyagok, core fájlok stb. törlése segíthet a helyzeten. Ha nem, meg kell várni, amíg a rendszergazda helyet nem csinál, illetve a nyomtatások befejeztével a spooler által igényelt hely felszabadul a lemezen.
Váratlan belső hiba, rendszerint a program számára kiosztott memóriahatárok megsértésekor jelentkezik. Akár saját programjaink hibás működése, akár valamelyik rendszerprogram hibája eredményezheti. A 'core dumped' üzenet jelzi, hogy az esetleges nyomkövetés céljaira egy core nevű állomány keletkezett, amelyik a rendszer memóriaképét és egyéb nyomkövetési információkat tartalmazza. (Ha nem használjuk fel hibakeresésre ezeket a fájlokat, célszerű rendszeresen irtani őket, mert kivált a mai terjedelmesebb Unixokban igen nagy helyet foglalnak el.