Praktični Bash
Kazalo:
- UVOD
- PREMIKANJE IN PROSTOR
- READLINE IN HISTORY
- GLOBBING IN BRACE EXPANSION
- ISKANJE
- POGANJANJE PROGRAMOV
- ZANIMIVI PROGRAMI IN EN PIKIČ O SKRIPTAH
- ZAKLJUČEK IN VIRI MODROSTI
- DODATEK
UVOD
Ta vodič bo predstavil praktične vidike uporabe bash-a, privzete konzole (lupine) na večini GNU/linux distribucij. Če slučajno uporabljate katero drugo lupino, najbrž ne bo problemov in lahko mirno berete naprej.
Zakaj bi sploh kdo uporabljal grdo[1], dolgočasno konzolo? Odgovor je preprost:
- v konzoli se mnogo stvari naredi hitreje kot z grafičnim vmesnikom (GUI)
- v konzoli se lahko dela stvari, ki se jih z GUI ne da
- in celo nekatere, ki se jih najbrž nikoli ne bo dalo
- ego boost :)
Da pridete do konzole poženite xterm, konsole, eterm,/.../ ali pa samo preklopite v prost terminal s CTRL+ALT+F4. Zadnje možnosti vam ne priporočam, ker boste potem najbrž imeli težave z branjem tega vodiča. ;) Skratka, na koncu vas pozdravi nekaj v smislu:
navaden@lynxlynxsp skripte $ |
To je bash poziv. Sem se pišejo ukazi, recimo echo, ki samo "odmeva" nazaj kar smo mu povedali:
navaden@lynxlynxsp skripte $ echo cogito ergo doleo cogito ergo doleo |
[1] to velja le za navadne terminale, tiste za X strežnik se da poljubno olepšati. No, tudi navadne terminale se da zelo polepšati z uporabo framebuffer-ja (prevaja se kot slikovni izravnalnik), ampak je postopek bolj zahteven in dolgotrajen.
PREMIKANJE IN PROSTOR
Trenutno lokacijo lahko ugotovimo z ukazom pwd:
navaden@lynxlynxsp skripte $ pwd /home/navaden/skripte |
Naokoli se premikamo z ukazom cd:
navaden@lynxlynxsp skripte $ cd /lgames/wesnoth/ navaden@lynxlynxsp wesnoth $ |
Sintaksa je `cd <pot>`. Če se pot začne s '/' je absolutna in bash začne iskati na korenskem imeniku (/).
V drugih primerih je pot relativna in bash začne iskati v trenutnem imeniku, zato tudi sledeča napaka.
navaden@lynxlynxsp skripte $ cd lgames/wesnoth/ bash: cd: lgames/wesnoth/: No such file or directory |
Da se vrnemo v prejšnji imenik, lahko uporabimo dostikrat spregledano možnost[2]:
navaden@lynxlynxsp skripte $ cd - /lgames/wesnoth navaden@lynxlynxsp wesnoth $ |
`cd` brez argumentov nas prestavi v domači imenik trenutnega uporabnika.
Vsebino trenutnega imenika ugotovimo z ls:
navaden@lynxlynxsp wesnoth $ ls aaaaaasdsasa fmt.sh skwiki tr updateCVS.sh~ wesnoth wiki3 a.out newwiki skwiki~ trfact wesdata wiki enote newwiki~ skwiki2 trfact~ weseder wiki2 enote~ newwiki3 tempOrarye updateCVS.sh weseder~ wiki2~ |
Hmm, čista zmeda. Da nam `ls` izpiše kaj so datoteke in kaj imeniki, mu dodamo možnost -F:
navaden@lynxlynxsp wesnoth $ ls -F aaaaaasdsasa fmt.sh* skwiki tr@ updateCVS.sh~ wesnoth/ wiki3 a.out newwiki skwiki~ trfact wesdata/ wiki enote* newwiki~ skwiki2 trfact~ weseder* wiki2 enote~ newwiki3 tempOrarye updateCVS.sh* weseder~ wiki2 |
Tako je bolje. Imena imenikov se končajo s '/', imena datotek, ki jih lahko poženete s '*' in simbolne povezave s '@'. Vse drugo so navadne datoteke [3]. Kot ste mogoče opazili, je kar nekaj datotek in datotek~. To so varnostne kopije in '~' je v kde njihova privzeta pripona.
V pomoč so že barve izpisa same - če teh nimate, uporabljajte `ls --color=always`.
Toda to ni vse, `ls` privzeto ne prikaže skritih datotek. Uporabite možnost -a:
navaden@lynxlynxsp wesnoth $ ls -a ./ enote~ newwiki3 tempOrarye updateCVS.sh~ wiki ../ fmt.sh* .ninja tr@ wesdata/ wiki2 aaaaaasdsasa .hiding.in.shadows skwiki trfact weseder* wiki2~ a.out newwiki skwiki~ trfact~ weseder~ wiki3 enote* newwiki~ skwiki2 updateCVS.sh* wesnoth/ |
Datoteke, ki se začnejo s piko, so skrite. '.' in '..' sta posebna imenika. '.' pomeni trenutni imenik (zato cd . nima smisla):
navaden@lynxlynxsp wesnoth $ pwd /lgames/wesnoth navaden@lynxlynxsp wesnoth $ cd . navaden@lynxlynxsp wesnoth $ pwd /lgames/wesnoth |
'..' pa starševskega:
navaden@lynxlynxsp wesnoth $ pwd /lgames/wesnoth navaden@lynxlynxsp wesnoth $ cd .. navaden@lynxlynxsp lgames $ pwd /lgames navaden@lynxlynxsp lgames $ cd - /lgames/wesnoth navaden@lynxlynxsp wesnoth $ cd ../.. navaden@lynxlynxsp / $ pwd / navaden@lynxlynxsp / $ cd - /lgames/wesnoth navaden@lynxlynxsp wesnoth $ cd ../../bin/ navaden@lynxlynxsp bin $ pwd /bin |
'.' je vseeno uporaben, recimo kot argument: `cp /usr/src/linux/.config .` namesto da bi pisali celotno trenutno pot je dovolj '.'.
Ker smo tečni, se nam zdi nepotrebno, da `ls -a` prikaže tudi '.' in '..'. V tem primeru si lahko pomagamo z -A:
navaden@lynxlynxsp wesnoth $ ls -A aaaaaasdsasa fmt.sh* newwiki3 skwiki2 trfact~ weseder* wiki2 a.out .hiding.in.shadows .ninja tempOrarye updateCVS.sh* weseder~ wiki2~ enote* newwiki skwiki tr@ updateCVS.sh~ wesnoth/ wiki3 enote~ newwiki~ skwiki~ trfact wesdata/ wiki |
Da zvemo kaj več kot le imena, ponavadi uporabimo `ls -lh` (izpis je skrajšan zaradi preglednosti):
navaden@lynxlynxsp wesnoth $ ls -lh total 294K -rw-r--r-- 1 navaden users 129K Apr 29 22:11 aaaaaasdsasa -rw-r--r-- 1 navaden users 0 Apr 3 21:31 a.out -rwxr-xr-x 1 navaden users 1017 Mar 10 20:40 enote* lrwxrwxrwx 1 navaden users 32 Apr 25 15:42 tr -> /home/navaden/dlTemping/wesnoth// -rw-r--r-- 1 navaden users 210 Mar 11 14:00 trfact -rw-r--r-- 1 navaden users 214 Mar 9 18:58 trfact~ -rwxr-xr-x 1 navaden users 205 May 8 16:47 updateCVS.sh* -rw-r--r-- 1 navaden users 147 Mar 11 20:07 updateCVS.sh~ drwxr-xr-x 5 navaden users 120 Apr 29 18:51 wesdata/ |
Možnost -l naredi izpis bolj podroben, -h pa zagotovi, da je lažje berljiv (human readable). `ls` za začetek izpiše skupno velikost vseh najdenih datotek.
Prvi stolpec predstavlja pravice lastnika (3. stolpec), skupine (4. stolpec) in vseh ostalih do te datoteke.
Drugi stolpec lahko zanemarite; šteje število povezav do datoteke.
Peti kaže velikost datoteke, ne pa tudi imenikov (prikaže velikost imenika brez vsebine).
Sledi še čas zadnje spremembe in ime. `ls` pokaže kam kažejo simbolne povezave, kar je lepo vidno na primeru.
Da bi izvedeli velikost imenika z vso njegovo vsebino vred uporabimo du -sh:
navaden@lynxlynxsp wesnoth $ du -sh wesdata/ 83M wesdata/ |
Primerjajte to s prej izpisano velikostjo (120 bajtov!). Možnost -h spet skrbi za berljiv izpis, -s pa du pove naj napiše samo skupno velikost. Brez tega bi izpisal velikosti vseh datotek v wesdata in globje.
Za preverjanje količine praznega prostora na disku uporabimo df
navaden@lynxlynxsp wesnoth $ df -h Filesystem Size Used Avail Use% Mounted on /dev/hda7 21G 17G 4.6G 79% / cachedir 21G 17G 4.6G 79% /lib/splash/cache /dev/hda6 19G 9.7G 9.0G 52% /lgames none 125M 0 125M 0% /dev/shm |
Če niste posebej particionirali diska, vas zanima samo količina na korenskem imeniku (/), torej prva vrstica. Možnost -h `df` pove da gre za hekerja.
[2] `cd -` izvede `cd "$OLDPWD" && pwd`. Ob večjih potrebah lahko uporabite pushd in popd.
[3] `man ls` za dve bolj redki dodatni priponi.
READLINE IN HISTORY
Bash uporablja readline knjižnico za branje vnosov (vrstic). Bližnjice so v emacs formatu, recimo uporabna C-l (CTRL+l), ki počisti zaslon (enako kot ukaz clean). Prav zna priti tudi C-u, ki izbriše trenutno vrstico. Za premikanje gor/dol po "ekranu" lahko uporabimo SHIFT+PGUP/PGDOWN. [4]
Nista pa to najbolj pomembni pridobitvi z readline. Daleč od tega! Predstavljam vam tipko tab (tabulator), eno izmed najbolj koristnih tipk v konzoli! [5]
Recimo da hočemo v /usr/local/share/man. Da vtipkamo `cd /usr/local/share/man` bi potrebovali kar nekaj časa, sploh če ne poznamo poti. Tu nas reši tab, dovolj je da vpišemo:
</code>
cd /u<tab>lo<tab>sh<tab>m<tab>
</code>
Poskusite, tab bo raztegnil pot, ki ustreza dosedanjemu nizu Za 1. tab to pomeni: v / je samo /usr na u, zato bo /u<tab> raztegnil na /usr. Če ima več možnosti, ne bo prikazal nič, zato pritisnite <tab> še enkrat in takrat vam jih bo prikazal vse in vi morate le še vnesti toliko znakov, da ostane samo še ena možna pot. Sliši se zakomplicirano, a ni - le poskusite.
navaden@lynxlynxsp wesnoth $ ls /usr/s<tab><tab> sbin/ share/ src/ |
Tenu se reče tab completition. To dela tudi na imenih uporabnikov, če uporabit predpono ~ (o pomenu kasneje):
navaden@lynxlynxsp wesnoth $ ~r ~root/ ~rpc |
na spremenljivkah ($):
navaden@lynxlynxsp wesnoth $ $U $UID $USER |
in na gostiteljih(@). [6]
Zelo praktična bližnjica je ALT+. :
navaden@lynxlynxsp wesnoth $ ls wesnoth/utils/CVS/ wesdata/ wesdata/: bin/ man/ share/ wesnoth/utils/CVS/: Entries Repository Root navaden@lynxlynxsp wesnoth $ du -sh <ALT+.><enter> 83M wesdata/ |
ALT+. se zamenja z zadnjim argumentom prejšnjega ukaza (vidno takoj).
Do prejšnjih ukazov lahko dostopamo s tipkama GOR/DOL, toda lahko kar traja, da najdemo kar smo hoteli.
Zato je tretja na seznamu najbolj uporabnih bližnjic PGUP/PGDOWN (page up). Je namreč stikalo za prirastno (incremental) iskanje po zgodovini ukazov (za razliko od GOR/DOL).
Na primer, če pritisnemo `c<PGUP>` bomo iskali po zgodovini ukazov le za takimi, ki se začnejo s 'c' ...
Velja še splošno opozorilo, linux razlikuje med malimi in VELIKIMI črkami. Tako so datoteka, Datoteka in daToTeka tri različne datoteke/imeniki!
Pomislite na to, ko vam ne bo uspelo priti v /etc/X11 ali zagnati BitchX?. ;)
Zdaj pa na hitro [8] o že omenjeni zgodovini. Bash shranjuje podane ukaze v datoteko .bash_history v uporabnikovem domačem imeniku (/home/navaden pri meni). Če ste pozabili kaj pomeni,da se ime začne s piko, si še enkrat preberite prejšnji del. Tam jih lahko pregledate, urejate in na hitro delate skripte.
Za uporaba mehanizmov zgodovine je značilen klicaj, par primerov:
- namesto ALT+. lahko uporabimo `!:$` (ne vem zakaj bi kdo to hotel)
- če hočemo uporabiti vse argumente prejšnjega ukaza, lahko to storimo z `!*`
navaden@lynxlynxsp wesnoth $ du -sh wesdata/ wesnoth/ 83M wesdata/ 201M wesnoth/ navaden@lynxlynxsp wesnoth $ ls !* ls -sh wesdata/ wesnoth/ wesdata/: total 0 0 bin/ 0 man/ 0 share/ wesnoth/: total 1.4M 56K ABOUT-NLS 44K Doxyfile 12K MANUAL.norwegian 36K aclocal.m4 0 fonts/ 12K MANUAL.polish /.../ |
Kot vidite, to vključuje čisto vse argumente, to so tudi možnosti. Izvedel se je `ls -sh wesdata/ wesnoth/`
- ^vzorec^zamenjava, kombinacija primerna za ljudi, ki se dostikrat zatipkajo. Ekvivalent je !!:s/vzorec/zamenjava/
navaden@lynxlynxsp wesnoth $ la -lah /usr/local/share/man/man5/lilo.conf.5 bash: la: command not found navaden@lynxlynxsp wesnoth $ ^a^s ls -lah /usr/local/share/man/man5/lilo.conf.5 -rw-r--r-- 1 root root 40K Jun 30 12:03 /usr/local/share/man/man5/lilo.conf.5 |
Kot vidite se prvo zamenja prvi najden vzorec s zamenjavo, potem se izpiše novi ukaz in končno še izvede.
- !niz bo zagnalo prvi ukaz v zgodovini, ki se začne z 'niz'. Meni osebno se zdi prirastno iskanje za take primere bolj praktično. [9]
[4] dober opis vseh bližnjic lahko najdete na http://mlug.ca/cms/content/view/80/57/
[5] isto delovanje ima tudi v kde in gnome okolju
[6] za še večjo uporabnost si poglejte Programmable Completion: http://www.caliban.org/bash/#completion
[8] oglejte si `man history`. Predstavil sem le izbrane možnosti - tiste, ki jih uporabljam sam
[9] ne more pa ga vedno nadomestiti - z `!?niz` bash išče niz na poljubnem mestu v ukazih, kar je s prirastnim iskanjem nemogoče
GLOBBING IN BRACE EXPANSION
Bash podpira (omejene) regularne izraze, čemur se iz zgodovinskih razlogov reče globbing. Deluje na datotekah (file globbing), z naslednjimi znaki:
- * označuje karkoli, kakršno število kakršnihkoli znakov (razen /). Opozoriti pa velja, da v primeru, če se nič ne ujema z vzorcem, bash * interpretira kot \*, torej dobesedno.
navaden@lynxlynxsp wesnoth $ ls a* aaaaaasdsasa a.out navaden@lynxlynxsp wesnoth $ ls c* ls: c*: No such file or directory navaden@lynxlynxsp wesnoth $ ls *c* trfact trfact~ navaden@lynxlynxsp wesnoth $ ls wesnoth/music/*.ogg wesnoth/music/elf-land.ogg wesnoth/music/wesnoth-1.ogg wesnoth/music/wesnoth-5.ogg /.../ |
Kot vidite se * raztegne na vsa imena datotek v trenutnem imeniku, ki se ujemajo s podanim vzorcem. Sam * se torej raztegne na vse datoteke v imeniku? Ne, globbing privzeto ne deluje za skrite datoteke, razen če piko podate posebej (.*). Tretji primer pokaže kako preprosto je poiskati datoteke z določeno "končnico".
- je torej lahko preprost nadomestek za ls:
navaden@lynxlynxsp wesnoth $ echo * aaaaaasdsasa a.out enote enote~ fmt.sh newwiki newwiki~ newwiki3 skwiki skwiki~ skwiki2 tempOrarye tr trfact trfact~ updateCVS.sh updateCVS.sh~ wesdata weseder weseder~ wesnoth wiki wiki2 wiki2~ wiki3 |
- [] označuje seznam sprejemljivih znakov; samo eden od teh znakov je lahko v vzorcu (na tem mestu). Z '-' zajamemo še vse vmesne znake.
navaden@lynxlynxsp wesnoth $ ls [aen]* aaaaaasdsasa a.out enote* enote~ newwiki newwiki~ newwiki3 navaden@lynxlynxsp wesnoth $ ls [aen]*[a3] aaaaaasdsasa newwiki3 navaden@lynxlynxsp wesnoth $ ls [aen][a3][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa][]* aaaaaasdsasa navaden@lynxlynxsp wesnoth $ ls [a-f]* aaaaaasdsasa a.out enote* enote~ fmt.sh* |
Prvi primer prikaže vse datoteke v trenutnem imeniku, ki se začnejo z a, e ali n. V drugem primeru se pa mora ime še končati z a ali 3. Tretji primer pokaže, da sta prazen seznam in ponovitve znakov neškodljiva/nesmiselena.
- ? označuje poljuben znak
navaden@lynxlynxsp wesnoth $ ls ??ki wiki navaden@lynxlynxsp wesnoth $ ls ??ki* wiki wiki2 wiki2~ wiki3 navaden@lynxlynxsp wesnoth $ ls ??ki[23]* wiki2 wiki2~ wiki3 navaden@lynxlynxsp wesnoth $ ls ??ki? wiki2 wiki3 |
- ^ označuje negacijo in se uporablja v navezi s seznamom:
navaden@lynxlynxsp wesnoth $ ls [^wnst]* aaaaaasdsasa a.out enote* enote~ fmt.sh* updateCVS.sh* updateCVS.sh~ navaden@lynxlynxsp wesnoth $ ls wi??[3] wiki3 navaden@lynxlynxsp wesnoth $ ls wi??[^3] wiki2 |
Torej znaki na seznamu ne smejo biti vsebovani, da se vzorec ujema.
Praktičen je še t.i. tilde expansion. Bash raztegne ~ na domači imenik ($HOME) uporabnika, ki ga je pognal. Tako lahko namesto `ls /home/navaden/.bashrc` uporabim `ls ~/.bashrc`. ~ se bo avtomatsko raztegnil, sicer ne vidno, a takoj ko vtipkamo `ls ~/<tab><tab>`, nam je jasno da kaže na pravo pot.
Če pa želimo brskati po domačem imeniku koga drugega (in imamo dovolj pravic), lahko že po vnosu tilde (~) pritisnemo tab in vidimo vse uporabnike, ki so na voljo (kot je že bilo omenjeno).
navaden@lynxlynxsp wesnoth $ ls ~r ~root/ ~rpc navaden@lynxlynxsp wesnoth $ ls ~rpc /dev/null |
Uporabnik rpc nima domačega imenika (/dev/null je digitalna črna luknja).
Od naslova nam ostane samo še brace expansion. Brace je zaviti oklepaj po angleško, z njimi pa delamo sezname, precej drugače kot globbing.
navaden@lynxlynxsp wesnoth $ echo {1,dve,korenje}
1 dve korenje
navaden@lynxlynxsp wesnoth $ ls {1,dve,korenje}
ls: 1: No such file or directory
ls: dve: No such file or directory
ls: korenje: No such file or directory
|
{kar,vpišemo,med,oklepaje,ločeno,z,vejicami} se bo razširilo v seznam s presledki. Pri echo je to lepo vidno, ker ni nič vidno; echo enostavno odjamra vse argumente nazaj. Pri ls je pa vsak argument druga pot. Zaenkrat nič presunljivega.
Lahko jih uporabimo namesto [], ko imamo na izbiro več nizov ([] izbere le en znak):
navaden@lynxlynxsp wesnoth $ ls {new,t,up}*
newwiki newwiki3 tr@ trfact~ updateCVS.sh~
newwiki~ tempOrarye trfact updateCVS.sh*
navaden@lynxlynxsp wesnoth $ ls *{sorbus,aria}*
ls: *sorbus*: No such file or directory
ls: *aria*: No such file or directory
navaden@lynxlynxsp wesnoth $ ls {new,t?[mf]}*
newwiki newwiki~ newwiki3 tempOrarye trfact trfact~
|
Še vedno pa velja, da se neujemajoč * uporabi dobesedno (drugi primer). V teh seznam lahko uporabljamo globbing.
Take izraze lahko poljubno gnezdimo, le pazite na presledke:
navaden@lynxlynxsp wesnoth $ echo {lepa,grda} {krava,bekica}
lepa grda krava bekica
navaden@lynxlynxsp wesnoth $ echo {lepa,grda}{krava,bekica}
lepakrava lepabekica grdakrava grdabekica
navaden@lynxlynxsp wesnoth $ echo {lepa,grda}\ {krava,bekica}
lepa krava lepa bekica grda krava grda bekica
navaden@lynxlynxsp wesnoth $ echo {lepa,grda}\ {krava,bekica}{,3}
lepa krava lepa krava3 lepa bekica lepa bekica3 grda krava grda krava3 grda bekica grda bekica3
|
Kot vidite bash raztegne oklepaje v vse možne kombinacije. Na primeru tudi lahko vidite vrstni red razširitve.
Naj omenim še, da bash od verzije 3 podpira {n..m} sintakso. To pomeni, da se bodo izpisala vsa števila med n in m. Na nizih to seveda ne deluje. Pri starejših verzijah je bilo potrebno napisati vse vmesne člene:
navaden@lynxlynxsp wesnoth $ echo {5..8}
5 6 7 8
navaden@lynxlynxsp wesnoth $ echo {5,6,7,8}
5 6 7 8
|
Opozorilo, seznami ne smejo vsebovati presledkov ali pa morajo ti biti ubežani (\ ). Podobno velja za vejice, ki tu ločujejo polja.
navaden@lynxlynxsp wesnoth $ echo {5,6,,,8}
5 6 8
navaden@lynxlynxsp wesnoth $ echo {5,6,\,,8}
5 6 , 8
|
Zdaj pa nekaj praktičnega. Recimo, da hočemo ustvariti 120 praznih datotek, ki imajo isto ime, le pripona bo število. Program touch ustvari prazno datoteko. To bi sicer zlahka izvedli s for zanko, ampak bi napisali trikrat več; naša rešitev je dosti bolj elegantna:
navaden@lynxlynxsp wesnoth $ touch Sorbus\ aria-{1..120}
|
to bo ustvarilo 120 datotek "Sorbus aria-N", kjer je N število.
Da jih izbrišemo naredimo podobno s programom rm (ALT+. anyone?):
navaden@lynxlynxsp wesnoth $ rm Sorbus\ aria-{1..120}
|
Zdaj pa nekaj res praktičnega (končno!).Recimo, da hočemo na svoj računalnik prenesti 1000 slik. Delo na roke takoj odpade, ftp dostopa do strežnika pa tudi nimamo. Na srečo so imena datotek generična "dsfN", kjer je N številka (prva datoteka je dsf0001.jpg). Za pobiranje bomo uporabili program wget in naše znanje o zavitih oklepajih. Za dejanske poskuse raje uporabite kar echo, da si ne nasmetite diska.
navaden@lynxlynxsp wesnoth $ wget -nc http://gentoo.prinas.si/dsf{0,1}{0..9}{0..9}{0..9}.jpg
|
Ta ukaz bi s strežnika prenesel vse datoteke od dsf0000.jpg do dsf1999.jpg in v tem izmišljenem primeru tudi en kup smeti za vse slike, ki jih ne najde. Boljše bi bilo, da bi uporabili:
navaden@lynxlynxsp wesnoth $ wget -nc http://gentoo.prinas.si/dsf0{0..9}{0..9}{0..9}.jpg
navaden@lynxlynxsp wesnoth $ wget -nc http://gentoo.prinas.si/dsf1000.jpg
|
Pa bi bilo takoj manj napak (samo še za prvo sliko).
Kadar so imena v takih oblikah (število mest za številko je stalno), ni nobenih problemov, dobiti datoteka1 datoteka2 ... datoteka1000 je pa malo težje:
navaden@lynxlynxsp wesnoth $ wget -nc http://gentoo.prinas.si/datoteka{1..9}{,0,1,2,3,4,5,6,7,8,9}{,0,1,2,3,4,5,6,7,8,9}
navaden@lynxlynxsp wesnoth $ wget -nc http://gentoo.prinas.si/datoteka1000
|
Kot vidite ne moremo več uporabiti bližnjice, ker pri vseh razen prvi števki potrebujemo na seznamu še ničen znak, drugače bi dosti številk izpustili (poskusite z `echo {1..9}{0..9}{0..9}`).
ISKANJE
Za iskanje datotek se uporabljata predvsem dva programa, find in {s,}locate. `locate` je hitrejši, ker išče po podatkovni bazi, je pa manj sposoben in zahteva vedno osveženo podatkovno bazo o vseh datotekah.
Večina distribucij bo že imela priložena `find` in `slocate` (`slocate` je samo bolj varna različica `locate`; `locate` je ponavadi simbolna povezava do `slocate`). Tudi za updatedb je ponavadi poskrbljeno, da se avtomatsko zažene na vsake toliko časa in posodobi `locate` bazo.
`locate`:
navaden@lynxlynxsp wesnoth $ locate bin laden /.../ sledi 5974 vrstic/datotek, ker je locate iskal prvo niz bin, potem pa še laden navaden@lynxlynxsp wesnoth $ locate bin\ laden navaden@lynxlynxsp wesnoth $ locate paradise navaden@lynxlynxsp wesnoth $ locate happiness navaden@lynxlynxsp wesnoth $ locate virtue navaden@lynxlynxsp wesnoth $ locate peace /usr/share/pixmaps/gaim/smileys/default/yahoo_peace.gif |
Že takoj po prvem poskusu bi nam moralo biti jasno, da `locate` išče iskalni niz na poljubnem mestu v vseh poteh. Ima sicer možnost -r, za uporabo regularnih izrazov, a po mojih izkušnjah ni vredu in zato uporabljam grep. Več o tem kasneje. Pomembno je vedeti, da je `locate` občutljiv na male in VELIKE črke, tako kot linux sam. Iskanje smisla, sMisla in Smisla bo torej za vsak iskalni niz proizvedlo drugačne rezultate.
Ker išče po bazi, gre brzinsko (prvi poskus najde približno v sekundi). `find` je za ista niza porabil 35s in pri tem še precej obremenil disk in sistem.
`locate` bo zaradi svoje narave za niz "s/Sa" pri meni našel kar nekaj ujemanj, `find` pa nobenega, ker išče samo datoteke (imenike ...) in te nikoli ne vsebujejo znaka '/'. [10]
`find`:
navaden@lynxlynxsp wesnoth $ find tr tr navaden@lynxlynxsp wesnoth $ find -name tr ./tr ./wesdata/share/wesnoth/translations/tr ./wesnoth/translations/tr navaden@lynxlynxsp wesnoth $ find wesdata/share/ -name elf-land.ogg wesdata/share/wesnoth/music/elf-land.ogg |
Find išče datoteke na podani poti (privzeto .) rekurzivno, to pomeni v vsej sledeči datotečni strukturi nižje, kar je njegova osnovna uporaba. Drugi primer to lepo prikaže (pri prvem ni rekurzije). Tretji primer prikazuje uporabo poti, kjer naj `find` išče. -name pove find, da naj išče argument (tr) in samo ta argument. Če bi želeli da pozabi na male/VELIKE črke, bi uporabili možnost -iname (i pride iz case insensitive):
navaden@lynxlynxsp wesnoth $ find -iname tr ./tr ./wesdata/tR ./wesdata/share/wesnoth/translations/tr ./wesnoth/translations/tr |
Če želimo da išče samo datoteke/imenike/simbolične povezave, mu to dopovemo s stikalom -type (f/d/l):
navaden@lynxlynxsp wesnoth $ find -iname tr -type f ./wesdata/tR navaden@lynxlynxsp wesnoth $ find -iname tr -type d ./wesdata/share/wesnoth/translations/tr ./wesnoth/translations/tr navaden@lynxlynxsp wesnoth $ find -iname tr -type l ./tr |
Iskalni niz lahko vsebuje znake za globbing in celo prave regularne izraze (z -{,i}regex):
navaden@lynxlynxsp wesnoth $ find -iname *o?a*u*e* -type f ./wesdata/share/wesnoth/images/human-royalguard-defend.png ./wesnoth/images/human-royalguard-defend.png navaden@lynxlynxsp wesnoth $ find -iregex ".*o.a.*u.*e.*" -type f ./wesdata/share/wesnoth/images/human-royalguard-defend.png ./wesnoth/images/human-royalguard-defend.png |
Če vam slučajno find pojamra nekaj o sintaksi in poti, dajte vzorec za iskanje v dvojne narekovaje. O regularnih izrazih si lahko preberete v `man grep`, vsekakor pa je to tema za bolj izkušene.
Vzorce lahko negiramo z -not (ali samo '!'):
navaden@lynxlynxsp wesnoth $ find wesdata/share/wesnoth/music/ -not -iname "wesnoth*" wesdata/share/wesnoth/music/ wesdata/share/wesnoth/music/main_menu.ogg wesdata/share/wesnoth/music/elf-land.ogg wesdata/share/wesnoth/music/frantic.ogg wesdata/share/wesnoth/music/underground.ogg |
To je find iskal vse datoteke v wesdata/share/wesnoth/music, ki v imenu nimajo niza 'wesnoth'.
Zanimivi možnosti sta tudi -maxdepth in -mindepth:
navaden@lynxlynxsp wesnoth $ find -type f -maxdepth 2 -mindepth 2 ./wesdata/tR ./wesnoth/config.h.dummy /.../ |
-mindepth 2 pove find da naj išče samo v imenikih 2 stopnji ali več nižje, -maxdepth pa naj išče največ v imenikih 2 stopnji ali manj nižje od iskalne poti. V našem primeru smo uporabili obe možnosti skupaj, kar pomeni da `find` išče samo v imenikih 2 stopnje nižje glede na trenutno pot (iskalno pot).
`find` je pa več kot le iskalec, lahko mu ukažemo, da na najdenih datotekah naredi poljubno operacijo (požene poljuben program)! V ta namen ima stikalo -exec:
navaden@lynxlynxsp wesnoth $ find -name tr -exec du -shc {} \;
0 ./tr
0 total
44K ./wesdata/share/wesnoth/translations/tr
44K total
0 ./wesnoth/translations/tr
0 total
|
Pomembno je vedeti le tri zadeve:
- uporabitije treba vsaj en {} kar se bo razširilo v pot do najdene datoteke. [11]
- ukaz se mora končati z " \;" tako da find ve kje mora nehati brati ukaze.
- podan ukaz se izvrši za vsako najdeno datoteko sproti, ne samo enkrat za vse. Zato je tudi `du` trikrat izpisal skupno velikost.
`find` podpira še mnogo drugih stikal in načinov iskanja. Oglejte si, tako kot vedno, `man find`.
Praktični primer z masovnim kopiranjem. Recimo da želimo narediti varnostno kopijo vseh naših službenih datotek:
navaden@lynxlynxsp wesnoth $ mkdir mossad
navaden@lynxlynxsp wesnoth $ mv mossad ..
navaden@lynxlynxsp wesnoth $ find -iname "*.mi6" -exec cp {} ../mossad/{}.bk \;
|
Na žalost `find` ne zna manipulirati poti v -exec, zato smo primorani narediti varnostne kopije z enakim imenom, le pripono lahko dodamo. Prvo pa sem ustvaril imenik z mkdir, zanalašč na napačnem mestu, tako da lahko predstavim še mv, ki služi za premikanje datotek/imenikov.
Če želimo v domačem imeniku najti vse slike jpg (poimensko, našel bo karkoli kar se konča na .jpg) večje od dveh megabajtov:
navaden@lynxlynxsp wesnoth $ find ~ -type f -size +2000k -iname *.jpg |
Če jih želimo še avtomatično zmanjšati za pol (`man xview`):
navaden@lynxlynxsp wesnoth $ find ~ -type f -size +2000k -iname *.jpg -exec xview -zoom 50 {} -dump jpeg {}-mala.jpg \;
|
Za konec še en kompleksen primer:
navaden@lynxlynxsp planeshift $ find /usr/src/linux/ -type f -iname *.h -or -iname *.c | xargs wc -l | grep total | awk '{vsota+=$1} END{print vsota}'
5997618
|
To izpiše število vrstic kode v trenutnem jedru (6 mio!). `find` začne iskati datoteke (-type f) v /usr/src/linux/, a samo tiste katerih ime se konča s '.c' ali (-or) pa '.h'.
Na žalost je bila količina podatkov prevelika, da bi zadevo naredil preprostejšo. Več o '|' kasneje.
[10] to se da spremeniti s stikalom -path
[11] lahko bi uporabili -exec brez {}, samo to ne bi imelo smisla
POGANJANJE PROGRAMOV
Ko v konzolo vtipkate ukaz in enter bo bash pogledal v sistemsko spremenljivko $PATH in po vseh poteh, ki jih ta vsebuje iskal vnešeni ukaz. Ob prvem zadetku bo nehal iskati in ga pognal. Če ga ne najde bo seveda zajamral. Ob vnašanju imena ne pozabite na <tab>!
navaden@lynxlynxsp planeshift $ echo $PATH /usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/i686-pc-linux-gnu/gcc-bin/3.3.5-20050130:/opt/blackdown-jdk-1.4.2.02/bin:/opt/blackdown-jdk-1.4.2.02/jre/bin:/usr/qt/3/bin:/usr/kde/3.4/bin:/usr/games/bin navaden@lynxlynxsp planeshift $ never<tab> neverball neverball-mapc neverputt |
V $PATH iz varnostnih razlogov ni . (trenutnega imenika). To pomeni, da če niste slučajno v enem od imenikov v $PATH, programov v tistem imeniku ne boste mogli zagnati:
navaden@lynxlynxsp planeshift $ eedit bash: eedit: command not found navaden@lynxlynxsp planeshift $ ls -l eedit -rwxr-xr-x 1 navaden users 31790152 Aug 8 22:10 eedit* |
To se reši z navidez nepotrebnim dodatkom:
navaden@lynxlynxsp planeshift $ ./eedit crystalspace.canvas.glx2d[SEVERITY=3]: Opening GLX2D /.../ |
V vseh drugih primerih je to nesmiselno. Dostikrat ljudje mislijo da je to edini način zaganjanja programov, ki niso na poti ($PATH) in si ustvarjajo dodatno delo v smislu:
navaden@lynxlynxsp / $ cd /lgames/psCVS/planeshift navaden@lynxlynxsp planeshift $ ./eedit |
ali pa:
navaden@lynxlynxsp / $ ./lgames/psCVS/planeshift/eedit |
ko je pa dovolj, da samo podamo pot (relativno ali absolutno, ni važno):
navaden@lynxlynxsp / $ lgames/psCVS/planeshift/eedit /.../ |
Da pa program sploh lahko zaženemo, mora biti izvršljiv (eXecutable). Če ni, še tab expansion ne bo delal. Natančno preverimo z ls -l:
navaden@lynxlynxsp planeshift $ ls -l psserver -rw-r--r-- 1 navaden users 61231140 Aug 8 22:06 psserver navaden@lynxlynxsp planeshift $ ./psserver bash: ./psserver: Permission denied |
V nizu z dovoljenji (prvi) ni nobenega x-a, zato programa ne more pognati niti root. V takem stanju so ponavadi datoteke, ki smo jih prenesli z interneta - prenevarno bi bilo, če bi bile takoj izvedljive. V drugem primeru sem na roko izpisal ime datoteke in bash je takoj povedal kaj je narobe.
Idealna priložnost za intermezzo o pravicah. Vsaka datoteka, imenik, naprava (...) ima zapis o pravicah.
Prvi znak pove ali gre za datoteko (-), imenik (d) ali pa za simbolično povezavo (l). Potem se trikrat ponovijo kombinacije znakov r, w, x, in -. Vsaka trojka označuje pravice, prva lastnika datoteke (u), druga privzeto skupine (g) v kateri je lastnik in tretja vseh ostalih (o) uporabnikov.
V prejšnjem primeru to pomeni, da lastnik lahko bere in piše po datoteki (rw-), ne more pa je zagnati; vsi ostali jo lako samo berejo (r--r--).
rwx pomeni read, write, execute (bere, piše, poganja), - pa da tega ne more (odvisno na katerem mestu je -).
Program za spreminjanje pravic je chmod:
navaden@lynxlynxsp planeshift $ chmod ug+x psserver navaden@lynxlynxsp planeshift $ ls -l psserver -rwxr-xr-- 1 navaden users 61231140 Aug 8 22:06 psserver* |
Ukazal sem mu naj lastniku in skupini doda pravico do poganjanja (+x). Če te pravice hočemo vzeti, uporabimo -x ipd. Za spreminjanje vseh pravic neankrat enostavno spustimo oznako tarče (u, g, o). [12]
Zdaj bom program lahko pognal:
navaden@lynxlynxsp planeshift $ ./psserver WARNING: could not load plugin 'crystalspace.graphics2d.null2d' /.../ |
Dosti o pravicah, čas je za praktičen problem. Pogosto uporabniki prenesejo kako *.bin ali *.run datoteko in jo ne znajo pognati. Nič posebnega, tako kot vedno je treba poskrbeti samo da je datoteka izvršljiva in jo pognati kot vse ostale programe.
Če dostikrat uporabljamo kak program, ki ni v $PATH, je nesmiselno vsakič pisati cele poti. Imamo več možnosti:
- absolutno pot do imenika kjer je program lahko dodamo v $PATH:
navaden@lynxlynxsp planeshift $ echo $PATH
/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/i686-pc-linux-gnu/gcc-bin/3.3.5-20050130:/opt/blackdown-jdk-1.4.2.02/bin:/opt/blackdown-jdk-1.4.2.02/jre/bin:/usr/qt/3/bin:/usr/kde/3.4/bin:/usr/games/bin
navaden@lynxlynxsp planeshift $ export PATH="${PATH}:/predolga/pot/do/nekega/programa"
navaden@lynxlynxsp planeshift $ echo $PATH
/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/i686-pc-linux-gnu/gcc-bin/3.3.5-20050130:/opt/blackdown-jdk-1.4.2.02/bin:/opt/blackdown-jdk-1.4.2.02/jre/bin:/usr/qt/3/bin:/usr/kde/3.4/bin:/usr/games/bin:/predolga/pot/do/nekega/programa
|
- lahko pa uporabimo alias:
navaden@lynxlynxsp planeshift $ alias alias cdmp3='cdmp3 --buffer --ogg' alias grep='grep --color=always' alias ls='ls -F --color=auto' alias nano='nano -w' |
Ukaz brez parametrov izpiše trenutne aliase. Kot vidite, v njih lahko uporabljamo rekurzijo (seveda dela samo prvič), ko jaz poženem `ls`, je isto kot da bi v novem sistemu pognal `ls -F --color=always`. Tukaj sicer ni nobenih dolgih poti, lahko bi pa bile, dodajmo primer:
navaden@lynxlynxsp planeshift $ alias vreme='superkaramba ~/dlTemping/liquid_weather_plus/liquid_weather.theme' navaden@lynxlynxsp planeshift $ alias alias cdmp3='cdmp3 --buffer --ogg' alias grep='grep --color=always' alias ls='ls -F --color=auto' alias nano='nano -w' alias vreme='superkaramba ~/dlTemping/liquid_weather_plus/liquid_weather.theme' |
Kot vidite poteka dodajanje aliasov popolnoma enako kot so izpisani v prvem primeru.
Če se nam kak alias slučajno zameri, se ga enostavno znebimo z unalias:
navaden@lynxlynxsp planeshift $ unalias vreme navaden@lynxlynxsp planeshift $ alias alias cdmp3='cdmp3 --buffer --ogg' alias grep='grep --color=always' alias ls='ls -F --color=auto' alias nano='nano -w' |
Pomembno: če želite te spremembe imeti v vseh konzolah, vedno, morate dodati te alias ali export vrstice v vaš ~/.bashrc! Drugače bodo aliasi in nova $PATH delali samo v trenutni konzoli do naslednjega zagona računalnika.
- lahko pa v enem od imenikov v $PATH ustvarimo simbolično povezavo, bližnjico, (premikanje programa tja ni priporočljivo). To naredimo s programom ln:
navaden@lynxlynxsp planeshift $ ln -s eedit ~/eedit navaden@lynxlynxsp planeshift $ ls ~ /.../ eedit@ /.../ |
Sintaksa je `ln -s KAJ KAM`. Kam kaže simbolična povezava lahko pogledamo z `ls -l` in readlink. Če to preverimo za naš primer, bomo hitro videli da smo naredili napako:
navaden@lynxlynxsp planeshift $ ls -l ~/eedit lrwxrwxrwx 1 navaden users 5 Aug 18 16:38 /home/navaden/eedit -> eedit |
Povezava kaže na eedit v trenutnem imeniku, kar v tem primeru naredi rekurzijo! Še dobro da bash to prepozna, drugače bi se najbrž sistem počasi sesul. Torej velja priporočilo, da se pri programu, ki ga hočemo povezati, uporabi absolutna pot:
navaden@lynxlynxsp planeshift $ ln -s $PWD/eedit ~/eedit navaden@lynxlynxsp planeshift $ readlink ~/eedit /lgames/psCVS/planeshift/eedit navaden@lynxlynxsp planeshift $ ~/eedit WARNING: could not load plugin 'planeshift.sound.soundmanager' /.../ |
Tako je bolje. :) Uporabil sem spremenljivko $PWD, ki vsebuje izpis ukaza `pwd`, tako da mi ni bilo treba iskati poti.
No, zdaj pa povežimo program nekam v pot:
root@lynxlynxsp planeshift # ln -s $PWD/eedit /usr/bin/eedit root@lynxlynxsp planeshift # ee<tab> WARNING: could not load plugin 'planeshift.sound.soundmanager' /.../ |
Ker sem izbral sistemsko pot, sem moral povezavo narediti kot uporabnik root (skrbnik sistema; ukaz su). Bash je pogledal v $PATH in tam našel eedit, zato je <tab> expansion lepo delal. Potem je avtomatsko prebral kam kaže povezava in pognal program.
Do zdaj smo uporabljali večinoma samo programe, ki se izvedejo hitro ali takoj. Recimo pa da zaženemo `kwrite`, zelo učinkovit urejevalni besedil: [13]
navaden@lynxlynxsp planeshift $ kwrite |
Hmm, zažene se že, ampak zdaj ne moremo več uporabljati konzole! Tega se rešimo, tako da prvo programu pošljemo signal SLEEP (CTRL+z) - program bo ustavil vse delo in čakal. Bash nam takoj vrne poziv, da pa `kwrite` lahko še naprej uporabljamo, poskrbi program bg:
</code>
(C-z)
[1]+ Stopped kwrite
navaden@lynxlynxsp planeshift $ bg
[1]+ kwrite &
</code>
S tem ukazom smo `kwrite` povedali naj teče v ozadju (BackGround?) in pusti konzolo na miru. Če bi slučajno želeli da je spet v ospredju (ForeGround?) v konzoli, uporabimo fg:
navaden@lynxlynxsp planeshift $ fg kwrite (C-c) |
Program sem zaključil s CTRL+c, kar ga je dobesedno ubilo.
Vsem tem delu z `bg` itd. se lahko preprosto izognemo - ob prvem zagonu uporabimo &:
navaden@lynxlynxsp planeshift $ kwrite & [1] 11411 navaden@lynxlynxsp planeshift $ |
kar `kwrite` takoj zažene v ozadju.
Opravila, ki tečejo v ozadju izpišemo z jobs:
navaden@lynxlynxsp planeshift $ jobs -l [1]+ 11411 Running kwrite & |
To nam da vse potrebne podatke za naše morilske namene. [1] je številka opravila, 11411 številka procesa (PID), sledi pa še cel ukaz.
Proces? Vsak tekoč program ima svoj proces, ki je predstavljen kot številka. Bolje rečeno, vsak program je svoj proces. Seznam vseh procesov dobite s ps:
navaden@lynxlynxsp planeshift $ ps ax
PID TTY STAT TIME COMMAND
1 ? S 0:00 init [3]
/.../
|
Predlagam da si ustvarite ta alias: ps="ps --forest". Tako bo v izpisu prikazana tudi hierarhija med procesi.
Zdaj pa morija. Program lahko ustavimo, tako da ubijemo njegov proces s `kill PID`, poimensko s `killall ime`, če pa teče v ozadju lahko ubijemo opravilo: `kill %N` (kjer je N številka opravila). V našem primeru so to: `kill 11411`, `killall kwrite` in `kill %1`.
killall vam ne priporočam, ker kot pravi ime, bo ubil vse procese, ki vsebujejo to ime! Nekaj več o [pobijanju procesov].
Če se zgodi da moramo pognati več ukazov enega za drugim in nočemo čakati da se vsak konča (ponavadi pri bolj dolgotrajnih ukazih), jih lahko vse podamo in ločimo s ;:
navaden@lynxlynxsp planeshift $ pwd; who likes bash?; whatis spam /lgames/psCVS/planeshift navaden pts/7 Aug 19 10:31 spam: nothing appropriate |
"Just one more thing". Večina GNU programov ne pove nič o delovanju, če jim tega posebej ne povemo (najbrž z --verbose). Kadar nismo prepričani, ali je program uspešno naredil kar mu je bilo ukazano, lahko preverimo njegov exit status, številko, ki je v veliki večini primerov 0, če je bil program uspešen in kaj drugega, če ni bil. To naredimo s pogledom na posebno spremenljivko $?:
navaden@lynxlynxsp planeshift $ cp npcclient.cfg npcclient.bekica navaden@lynxlynxsp planeshift $ echo $? 0 navaden@lynxlynxsp planeshift $ cp cash more\ cash cp: cannot stat `cash': No such file or directory navaden@lynxlynxsp planeshift $ echo $? 1 navaden@lynxlynxsp planeshift $ echo $? 0 |
$? vedno vsebuje exit status zadnjega pognanega ukaza, zato je zadnji primer 0 - prejšnji `echo` je bil uspešen (seveda, saj smo videli).
[12] chmod podpira tudi bolj napredno in zmogljivejšo sintakso s številkami. Kot vedno lahko več o tem zveste v `man chmod`
[13] od tu naprej primeri zahtevajo da ste v grafičnem okolju. Uporabljen je kwrite, del KDE - zamenjajte s čem podobnim, če nimate KDE.
ZANIMIVI PROGRAMI IN EN PIKIČ O SKRIPTAH
V tem poglavju bom predstavil par zanimivih in manj znanih programov, ki pa so vseeno vedno prisotni (večina je del coreutils). Na hitro tudi nekaj o skriptiranju.
nohup nam omogoča, da zaženemo program in zapremo/ubijemo konzolo s tem da bo program še vedno tekel. Posledično program ne bo nič izpisoval v konzolo, ampak se bo privzeto vse pisalo v datoteko ./nohup.out .
Mogoče bi kdo pomislil, da je za to dovolj da program pošljemo v ozadje. Ni. Konzola je namreč starševski proces programov, ki jih iz nje zaženemo. Če ubijemo starše, bodo otroci naredili samomor ali pa postali zombiji. Res! In to zombiji najhujšega tipa - zombi procesov se ponavadi lahko znebimo samo s ponovnim zagonom računalnika.
Primer uporabe. Recimo da doma poganjamo apache, ki skrbi za našo spletno stran. Gremo k babici in ji hočemo pokazati našo prelestno stvaritev, a ugotovimo da se je medtem sesul strežnik (apache). Tu nas reši `nohup` - enostavno se priklopimo na naš domači računalnik (recimo prek ssh) in apache ponovno zaženemo z `nohup httpd &`.
Naslednji program je time. Z njim preprosto merimo koliko časa se kak program izvaja:
navaden@lynxlynxsp planeshift $ time find .. -iname "gold" real 0m2.052s user 0m0.059s sys 0m0.158s |
Pomembna je vrstica real, ki prikazuje dejanski porabljen čas.
Program sleep nam omogoča pavziranje in zakasnelo poganjanje. [14] Čas je lahko v sekundah (s), minutah (m), urah (h) ali dnevih (d) in številka je lahko decimalna:
navaden@lynxlynxsp planeshift $ sleep 2s |
Za lažjo predstavo bom uporabil `time`:
navaden@lynxlynxsp planeshift $ time sleep 5s real 0m5.004s user 0m0.002s sys 0m0.001s navaden@lynxlynxsp planeshift $ time sleep 0.1m real 0m6.004s user 0m0.001s sys 0m0.002s |
Recimo da hočemo čez dve uri pognati korenine:
navaden@lynxlynxsp planeshift $ sleep 2h; korenine |
look je še manj znan program, ampak pride prav ko ne znamo v angleščini česa pravilno napisati:
navaden@lynxlynxsp planeshift $ look unconsci unconscienced unconscient unconscientious unconscientiously unconscientiousness unconscionable unconscionableness unconscionably unconscious unconsciously unconsciousness |
Samo vnesemo prvih nekaj črk ...
yes je tako preprost program, da je še `echo` bolj napreden. Ko ga poženemo, privzeto izpisuje "yes" dokler ga ne prekinemo. Omenjam ga samo iz enega razloga - lahko nadomesti `clean` (C-l).
`clean` izbriše samo vse kar je trenutno na zaslonu, vse od prej ostane - to lahko preverimo s SHIFT+PGUP. `yes` bo pa tako hitro nasmetil konzolo, da ne bo od prejšnjih "zaslonov" ostalo nič.
reset ponastavi vse vrednosti v lupini - koristno, če vam jo je uspelo popačiti do neberljivosti.
Tekočim programom lahko z renice spremenimo prioriteto (niceness), tako da tečejo hitreje in požrejo več resursov (in obratno). Privzeto se uporabniški programi poganjajo s prioriteto 0, vse kar je nižje je torej hitrejše. Za zniževanje potrebujete skrbniške pravice in to z dobrim razlogom - s tem se ni preveč za igrati, ker si lahko onesposobite sistem.
navaden@lynxlynxsp wesnoth $ renice 5 26912 26912: old priority 0, new priority 5 |
`renice` sprejema PID-e kot argument (spomnite se `ps`), ne imen programov. Če se slučajno zgodi, da že ob zaganjanju programa veste, da ga bi radi imeli na določeni prioriteti, lahko uporabite nice.
Od eksotov ostane še ukaz tee, a prvo moramo spoznati pipe (cevi?). Vsakič ko nam program kaj izpiše to izpiše na t.i. standardni izhod (stdout) in vsakič ko mu mi kaj povemo, posluša na standarnem vhodu (stdin). Kadar pa jamra, ponavadi uporabi standardni izhod za napake (stderr).
Cev nam omogoča da standardni izhod enega programa napeljemo v standardni vhod drugega. Program less se uporablja za branje besedil. Razlomi jih na strani in tako omogoča mirno branje, lahko navigacijo in iskanje (/niz). Za razliko od more tudi ne piše po konzoli. Res da sem malo asketa, ampak `less` je dejansko boljši od `more`. ;)
Recimo da smo s `find` poiskali nekaj (mnogo) datotek. Da bi jih v miru in po vrsti prebrali, lahko uporabimo `less`:
navaden@lynxlynxsp herbarij4 $ find /usr/bin -size +50k | less
navaden@lynxlynxsp herbarij4 $ find /usr/bin -size +3000k -exec less {} \;
navaden@lynxlynxsp herbarij4 $ less ~/.bash_history
|
S prvim ukazom bi imena lepo prebrali v `less`, z drugim bi pa prebrali vsebino vsakega posebej. Tretji primer kaže običajno invokacijo `less`.
tail privzeto izpiše samo zadnjih deset vrstic datoteke ali kar dobi preko standardnega vhoda. Tako lahko npr. omejimo dolg izpis `ps ax`:
navaden@lynxlynxsp wesnoth $ ps ax | tail -n 3 14155 ? S 0:00 kio_uiserver [kdeinit] 14916 pts/8 R+ 0:00 ps ax 14917 pts/8 S+ 0:00 tail -n 3 |
Podobno funkcionalnost ima head, samo da ta izpiše prvih deset vrstic, ne zadnjih (že imena sama vse povedo). Seveda ni treba uporabljati cevi:
navaden@lynxlynxsp wesnoth $ head -n 5 ~/.bash_history sed -i 's/\. */,/' vrste wc -l vrste grep -c "-" grep -c "-" vrste grep "-" vrste | head |
Super primer. V izpisu vidite tudi program wc, ki prešteva znake, besede in vrstice (-l):
navaden@lynxlynxsp wesnoth $ wc -l ALT+. 12297 /home/navaden/.bash_history |
Za še bolj praktični prikaz uporabnosti cevi bomo uporabili grep. `grep` je čista poezija, eden od najbolj pogosto uporabljanih programov. Ni čudno, saj je filter, iskalec - z njim iz tisočih vrstic in datotek hitro najdemo/izvlečemo kar želimo (vzorec):
navaden@lynxlynxsp wesnoth $ grep tee ~/.bash_history man tee |
Ena sama vrstica! Prej smo ugotovili da je vseh skupaj 12297, predstavljajte si, da bi šli ročno iskati po datoteki. Nič takega boste rekli, to podpira vseh deset tisoč urejevalnikov besedil. Dosti manj jih pa podpira regularne izraze (spominja na globbing), rekurzivno iskanje in najbrž nobenega ne moremo uporabiti kot filter.
navaden@lynxlynxsp wesnoth $ grep "^g[el].*" ~/.bash_history glxgears glxinfo | grep render # as a test gettext --version gettext --help gerp "source package" urpmi-sl.po |
Tu smo v datoteki iskali vrstice, ki se začnejo (^ pomeni začetek vrstice) z 'g', temu pa sledi 'e' ali 'l' in še karkoli (.* pomeni poljubno število poljubnih znakov).
Kolikokrat se pojavi grep v isti datoteki:
navaden@lynxlynxsp wesnoth $ grep -c grep ~/.bash_history 1433 navaden@lynxlynxsp wesnoth $ grep grep ~/.bash_history | wc -l 1433 |
Toda ta številka vara - `grep` preišče vrstico za vrstico, toda ko v eni najde iskani niz, gre takoj v naslednjo. To pomeni da tu niso prešteti (-c kot count) vsi 'grep', ampak samo vse vrstice v katerih se pojavlja (kar potrdi alternativa z `wc`). V resnici jih je 1606.
Če bi hoteli dobiti samo vrstice v katerih se pojavi grep, sed in ls, ne pa tudi boot in flora:
navaden@lynxlynxsp wesnoth $ grep grep ~/.bash_history | grep sed | grep ls | grep -v "flora" | grep -v boot sed -n 's,.*file *= *"\([^"]*\)".*,\1,p' data/effects/spells/summon_missile.xml | grep -v "\.spr" | sort | uniq sed -n 's,.*file *= *"\([^"]*\)".*,\1,p' data/effects/spells/summon_missile.xml.bk | grep -v "\.spr" | sort | uniq ls `''sed 's/:/ /'<<<$PATH''` | grep -i root ls `''sed 's/:/ /g'<<<$PATH''` | grep -i root |
Stikalo -v pomeni negacijo. Tu lahko vidite, da je število cevi praktično neomejeno in kako preprosto se filtrira z `grep`. Stikalo -i pove `grep` naj se ne briga ali je niz v malih ali velikih črkah (grep -i grep bi našel tudi GrEP?, grEp, Grep...).
Še en primer `grep`-a kot filtra. Da ugotovimo, če je na grafični kartici sploh vključeno 3d pospeševanje, lahko uporabimo glxinfo:
navaden@lynxlynxsp wesnoth $ glxinfo | wc -l 153 |
Kar dosti podatkov, sploh ker je vse 3d žargon. Ko enkrat ugotovimo, da so iskani podatki že čisto na začetku, lahko preverjanje zelo skrajšamo:
navaden@lynxlynxsp wesnoth $ glxinfo | head -n3 name of display: :0.0 display: :0 screen: 0 direct rendering: Yes |
Uporaba `head` ni slaba ideja, toda kaj če se kdaj ta vrstica premakne nižje, drugam? Zato je bolje uporabiti `grep`, ker bo preiskal vse vrstice:
navaden@lynxlynxsp wesnoth $ glxinfo | grep render direct rendering: Yes OpenGL renderer string: GeForce FX 5700LE/AGP/SSE/3DNOW! navaden@lynxlynxsp wesnoth $ glxinfo | grep rendering direct rendering: Yes navaden@lynxlynxsp wesnoth $ glxinfo | grep direct direct rendering: Yes |
Prvi iskalni niz je bil očitno presplošen.
dmesg izpiše vse kar je povedalo jedro med zagonom. Precej dolgočasno, če nam vsa strojna oprema dela. Uporabili ga bomo za prikaz uporabe konteksta:
navaden@lynxlynxsp wesnoth $ dmesg | grep -A1 memory Freeing initrd memory: 426k freed NET: Registered protocol family 16 -- Freeing unused kernel memory: 164k freed Adding 987988k swap on /dev/hda3. Priority:-1 extents:1 navaden@lynxlynxsp wesnoth $ dmesg | grep -B1 memory checking if image is initramfs... it is Freeing initrd memory: 426k freed -- Mounted devfs on /dev Freeing unused kernel memory: 164k freed navaden@lynxlynxsp wesnoth $ dmesg | grep -B1 -A1 memory checking if image is initramfs... it is Freeing initrd memory: 426k freed NET: Registered protocol family 16 -- Mounted devfs on /dev Freeing unused kernel memory: 164k freed Adding 987988k swap on /dev/hda3. Priority:-1 extents:1 navaden@lynxlynxsp wesnoth $ dmesg | grep -C1 memory checking if image is initramfs... it is Freeing initrd memory: 426k freed NET: Registered protocol family 16 -- Mounted devfs on /dev Freeing unused kernel memory: 164k freed Adding 987988k swap on /dev/hda3. Priority:-1 extents:1 |
Stikalo -A n pove `grep` naj poleg najdenega niza izpiše še n sledečih (After) vrstic. -B n podobno pove naj izpiše prejšnjih (Before) n vrstic. -C n kot kontekst je pa ekvivalent uporabi obeh hkrati z istimi številkami (glejte zadnja dva primera) - izpiše n vrstic na obeh straneh najdenega niza. Posamezne kontekste `grep` loči s '
'.
Malo prej smo ugotovili, da je v jedru šest milijonov vrstic kode. Zanima me, če slučajno kak vsebuje niz " LPN ". Da ne bo treba pisati vseh imen datotek ali dolgih globbing vzorcev, ima `grep` stikalo -R (Rekurzivno). Samo podamo mu imenik in `grep` bo preiskal vse stvari v njem in nižje v datotečni strukturi:
navaden@lynxlynxsp wesnoth $ grep -R " LPN " /usr/src/linux/ /usr/src/linux/drivers/net/tulip/pnic2.c: * Bit 15 - LPN is 1 if all above bits are valid other wise 0 |
Še ena uporabna stran `grep -v`. Ko nam huda prede in po forumih iščemo pomoč, nam kdo reče lahko naj mu pokažemo nastavitven[oe] datotek[oe], recimo xorg.conf.
navaden@lynxlynxsp wesnoth $ wc -l /etc/X11/xorg.conf 475 /etc/X11/xorg.conf |
Uff, tole bi pa bil zalogaj za forum, bolj preprosto rečeno spam. Zmeda in naveličanost - koga brigajo vsi komentarji in prazne vrstice, ko iščemo pomoč je treba pokazati samo relevantne podatke:
navaden@lynxlynxsp wesnoth $ grep -v "^#" /etc/X11/xorg.conf | grep -v "^ *$" | wc -l 91 |
Vidite razliko? V prvem primeru bi poslali skoraj 400 odvečnih vrstic! S prvim `grep` smo zanemarili vse vrstice-komentarje (o tem kmalu), z drugim pa vse prazne vrstice (s presledki ali brez). Za dejanski izpis samo odstranite `wc -l`.
Končno je prišel čas za `tee`. Recimo da hočemo najti cel kup enih datotek po zapletenem vzorcu (tako da `ls` odpade) in pri tem dobiti njihovo število in še imena.
navaden@lynxlynxsp planeshift $ find -type f -size -100k -group users -name "*[^Elgf]ist*" ./src/common/engine/netpersist.cpp ./src/common/engine/netpersist.h ./docs/history.txt navaden@lynxlynxsp planeshift $ find -type f -size -100k -group users -name "*[^Elgf]ist*" | wc -l 3 |
Narediti vsako posebej ni problem. Težave bi bila pri bolj zapletenih primerih, ko npr. ukaza ne moremo (ali nočemo) ponoviti. V takem primeru pride prav `tee`, ki podvoji izpis:
navaden@lynxlynxsp planeshift $ find -type f -size -100k -group users -name "*[^Elgf]ist*" | tee seznamImen | wc -l 3 navaden@lynxlynxsp planeshift $ more seznamImen ./src/common/engine/netpersist.cpp ./src/common/engine/netpersist.h ./docs/history.txt |
`tee` shrani kar mu je bilo poslano v datoteko in podatke neokrnjene pošlje naprej v obdelavo. Z njim lahko izhod pošljemo še na druge terminale, če nam zapis v datoteko ni všeč. Namesto datoteke napišemo pot do virtualne naprave željene konzole, recimo /dev/pts/2 (to lahko ugotovimo z ukazom tty).
Mogoče se kdo sprašuje zakaj še nisem omenil cat. To je iz čisto preprostega razloga, `cat` je najbolj pretirano in po nepotrebnem uporabljan program od vseh omenjenih. Zakaj? Kot prvo, večina ga uporablja za izpis datotek, ko pa je more (tudi less) dosti bolj praktičen, kot drugo pa je pogosto nepotreben člen v mnogih ceveh. Nepotreben zato, ker večina programov/filtrov lahko sprejme datoteko kot argument. Primer:
navaden@lynxlynxsp wesnoth $ cat updateCVS.sh | grep cvs cvs -z3 update -dP && navaden@lynxlynxsp wesnoth $ grep cvs updateCVS.sh cvs -z3 update -dP && |
Njegov osnovni namen je združevanje datotek (conCATenation), ampak to je bolj redko rabljeno.
En praktičen primer uporabe je oštevilčevanje vrstic:
navaden@lynxlynxsp wesnoth $ cat -n a.out
1 I don't care who you are, Fatso. Get those reindeer off my roof.
2 -------------------------------------------------------------------------
3 I never believed in Santa Claus because I knew no white dude would come
4 into my neighborhood after dark.
5 -- Dick Gregory
navaden@lynxlynxsp wesnoth $ grep -n "" a.out
1:I don't care who you are, Fatso. Get those reindeer off my roof.
2:-------------------------------------------------------------------------
3:I never believed in Santa Claus because I knew no white dude would come
4:into my neighborhood after dark.
5: -- Dick Gregory
|
...ker to naredi dosti lepše kot ta trik z `grep`.
Če večkrat zapored poganjate isti nabor ukazov, jih lahko dodate vse v en alias:
navaden@lynxlynxsp wesnoth $ alias dobrojutro="xmms -p &; pwd; date" |
date izpiše datum in ostale časovne podatke. Ne pozabite da ga morate dodati v ~/.bashrc , če želite da se alias trajno ohrani.
Lahko pa jih preprosto vpišete v prazno datoteko, dodate v prvo vrstico #!/bin/bash , datoteko naredite izvršljivo in jo po možnosti še povežete nekam v $PATH . To je to, vaša prva skripta.
Vanjo lahko dodajate komentarje; označuje jih znak '#' . Vse za tem znakom bo interpreter (bash - prva vrstica) spregledal. [15] Seveda komentarji delajo tudi izven skript:
navaden@lynxlynxsp wesnoth $ pwd # Sorbus aria! /lgames/wesnoth navaden@lynxlynxsp wesnoth $ echo # Sorbus aria! navaden@lynxlynxsp wesnoth $ echo '# Sorbus aria!' # Sorbus aria! navaden@lynxlynxsp wesnoth $ echo \# Sorbus aria! # Sorbus aria! |
Če hočemo izpisati '#', ga moramo ubežati, ali pa dati med narekovaje.
Preusmeritve. Zelo praktična zadeva, eno od njih smo tudi že spoznali - cevi. S '>' preusmerimo celoten programov izpis v datoteko:
navaden@lynxlynxsp wesnoth $ fortune -s > less navaden@lynxlynxsp wesnoth $ more less A shortcut is the longest distance between two points. |
Če datoteka ne obstaja, bo ustvarjena. Če že obstaja, bo prepisana! fortune je pa sila posrečen program, ki izpisuje razne navedke in pesmice. Idealno za v ~/.bashrc. ;)
S '>>' pa samo pripnemo izpis na konec datoteke:
navaden@lynxlynxsp wesnoth $ echo "Facilius per partes in cognitionem totius adducimur (Seneca)" >> less navaden@lynxlynxsp wesnoth $ more less A shortcut is the longest distance between two points. Facilius per partes in cognitionem totius adducimur (Seneca) |
S '<' preusmerimo datoteko na programov standarni vhod:
navaden@lynxlynxsp wesnoth $ tr '[a-z]' '[A-Z]' < less A SHORTCUT IS THE LONGEST DISTANCE BETWEEN TWO POINTS. FACILIUS PER PARTES IN COGNITIONEM TOTIUS ADDUCIMUR (SENECA) |
To pride prav v primerih kot je tr, ki ne more vzeti datoteke kot argument. `tr` se uporablja za translacijo znakov:
navaden@lynxlynxsp wesnoth $ tr '[a-z]' '[a-cD-Mn-z]' < less A sHortcut Is tHE LonGEst DIstancE bEtwEEn two poInts. FacILIus pEr partEs In coGnItIonEM totIus aDDucIMur (SENEca) |
Oba argumenta sta enako dolga, zato je `tr` vsak znak v prvem zamenjal z istoležnim v drugem argumentu. Drugi argument je čisto navaden seznam, le vmes je par znakov velikih (pomembno je da je zvezen).
Namesto '<' bi lahko uporabili cev.
Enkrat sem že omenil /dev/null , priročno črno luknjo. To pomeni da vse kar pošljemo tja izgine brez sledu. Idealno za uporabo pri preusmeritvah. Recimo da nočemo da nam zagnani program karkoli pove:
navaden@lynxlynxsp wesnoth $ firefox & [1] 12361 navaden@lynxlynxsp wesnoth $ No running windows found [1]+ Done firefox |
Zagnal sem ga v ozadju pa je vseeno uspel nekaj načečkati po konzoli. Še dobro da nisem ničesar pisal, ker bi mi tekst vstavil kar vmes. Dokler v tekstu ni nobenega ukaza še ni tako hudo, a nikoli ne veš ...
navaden@lynxlynxsp wesnoth $ firefox > /dev/null & [1] 12401 navaden@lynxlynxsp wesnoth $ No running windows found [1]+ Done firefox >/dev/null |
Bleh, še vedno ni dovolj - očitno je tisti tekst izpisan na standardni izhod za napake (stderr), mi smo pa preusmerili samo stdout. Oba naekrat preusmerimo z '&>':
navaden@lynxlynxsp wesnoth $ firefox &> /dev/null & [1] 12441 navaden@lynxlynxsp wesnoth $ [1]+ Done firefox >&/dev/null |
stderr je file descriptor številka 2, to pomeni, da če hočemo pozabiti samo napake in opozorila:
navaden@lynxlynxsp wesnoth $ firefox 2> /dev/null & [1] 12651 navaden@lynxlynxsp wesnoth $ [1]+ Done firefox 2>/dev/null |
Standardni izhod ima številko ena, ampak jo lahko izpustimo (poglejte prve primere).
Če hočemo celoten izpis programa, vključno z napakami (stderr), pripeti v datoteko, '&>>' ne bo vredu, ker ne dela. Prvo moramo stderr preusmeriti v stdout (2>&1), tako da je vse v enem toku podatkov in potem tega še pripeti v datoteko:
navaden@lynxlynxsp wesnoth $ firefox >> less 2>&1 & [1] 12808 navaden@lynxlynxsp wesnoth $ more less A shortcut is the longest distance between two points. Facilius per partes in cognitionem totius adducimur (Seneca) No running windows found |
Vrstni red je pomemben!
Preusmeritve lahko seveda kombiniramo:
navaden@lynxlynxsp wesnoth $ echo chameacytisus >> napake navaden@lynxlynxsp wesnoth $ more napake chamaecytisus navaden@lynxlynxsp wesnoth $ tr '[aeiou]' '[oueai]' < less >> less 2>> napake navaden@lynxlynxsp wesnoth $ more less A shortcut is the longest distance between two points. Facilius per partes in cognitionem totius adducimur (Seneca) No running windows found A shartcit es thu langust destoncu butwuun twa paents. Foceleis pur portus en cagneteanum tateis oddicemir (Sunuco) Na rinneng wendaws faind navaden@lynxlynxsp wesnoth $ more napake chamaecytisus |
Tu smo `tr` poslali podatke iz datoteke less in mu povedali naj vanjo doda rezultat, ob napakah pa naj te doda v datoteko napake. V našem primeru očitno ni bilo napak, saj je datoteka napake na koncu enaka.
iconv in recode sta dva programa, ki pretvarjata besedila v različne kodne nabore. Prideta (en ali drug) še kako prav, sploh če uporabljate unicode in morate poslati besedilo komu z revnim cp1250 ali iso8859-2 naborom znakov. Brez pretvorbe bi bili vsi eksotični znaki izmaličeni (recimo šumniki).
navaden@lynxlynxsp wesnoth $ iconv -t iso-8859-2 -f utf-8 less > less2 navaden@lynxlynxsp wesnoth $ recode cp-1250..iso8859-2 less |
`iconv` izpiše rezultat na stdout, zato ga moramo preusmeriti. Nikoli ne smemo brati in pisati v isto datoteko. Enostavno ne bo delalo (razen če v datoteko pripenjamo nove podatke). Vse poznane nabore nam programa izpišeta, če jima podamo stikalo -l.
Zdaj ko poznamo preusmeritve, lahko začnemo pisati skripto kar tako:
navaden@lynxlynxsp wesnoth $ echo ' #!/bin/bash' > skripta navaden@lynxlynxsp wesnoth $ more skripta #!/bin/bash navaden@lynxlynxsp wesnoth $ echo >> skripta navaden@lynxlynxsp wesnoth $ more skripta #!/bin/bash |
`echo` brez argumentov izpiše samo prelom vrstice ('\n'). Če hočemo naenkrat vnesti več vrstic lahko uporabimo trik z narekovaji:
navaden@lynxlynxsp wesnoth $ echo 'echo "Pozdravljeni $(whoami)!" > SPREMENLJIVKA="Sorbus aria!" > echo $SPREMENLJIVKA > ' >> skripta navaden@lynxlynxsp wesnoth $ more skripta #!/bin/bash echo "Pozdravljeni $(whoami)!" SPREMENLJIVKA="Sorbus aria!" echo $SPREMENLJIVKA |
Bash bo namreč iskal drugi enojni narekovaj in ne bo nehal brati dokler ga najde. Enostavno pritisnemo enter in že pišemo v novo vrstico. Seveda bi skripto najbrž lažje ročno vpisali v datoteko, tu sem le prikazal zanimivo alternativo.
Skripto naredite izvršljivo in jo poženite.
navaden@lynxlynxsp wesnoth $ ./skripta Pozdravljeni navaden! Sorbus aria! navaden@lynxlynxsp wesnoth $ echo $SPREMENLJIVKA |
Razlaga: $(ukaz) bo izvršilo "ukaz" in se nadomestilo z njegovim izpisom. V naslednji vrstici smo ustvarili spremenljivko SPREMENLJIVKA (brez $ pred imenom!) in jo v naslednji izpisali (povsod drugod spremenljivko določa znak $ pred imenom!). Očitno je uspelo, zanimivo pa je, da po končanju skripte SPREMENLJIVKA ni več definirana - drugi `echo` ni izpisal nič. (sploh ni definirana - tab expansion ni delal)
To je pa zato, ker se vsaka skripta zažene v svoji lupini, svojem bashu. Zato lahko v skriptah spreminjamo tudi zelo pomembne spremenljivke (recimo PATH=koleraba), pa najbrž ne bo nobene škode, ker bojo spremembe veljale samo za skriptino lupino.
Bash seveda pozna if stavke in možno je kar precej različne sintakse (skladnje ^^).Osnovna je tale:
navaden@lynxlynxsp wesnoth $ if [ "$PWD" == wesnoth ]; then echo hmmm; else echo "a b c"; fi a b c navaden@lynxlynxsp wesnoth $ if [ "$PWD" != wesnoth ]; then echo hmmm; else echo "a b c"; fi hmmm |
Med oglatimi oklepaji mora vedno biti presledek (oklepaj je ukaz!). Spremenljivke vedno dajte v dvojne narekovaje, razen če veste da ne vsebujejo presledkov, tabulatorjev ali prelomov vrstic. Seveda jih ni treba tlačiti v eno vrstico:
navaden@lynxlynxsp wesnoth $ if [ "$PWD" != wesnoth ] > then echo hmmm > else echo "a b c" > fi hmmm navaden@lynxlynxsp wesnoth $ echo $PWD /lgames/wesnoth navaden@lynxlynxsp wesnoth $ echo '$PWD' $PWD navaden@lynxlynxsp wesnoth $ echo "$PWD" /lgames/wesnoth |
Enojni narekovaji ohranijo pomen niza - kot da bi bil vsak znak ubežan, zato se spremenljivka tam ni razširila.
Kot ste morda opazili, zadnjih nekaj poskusov sploh nismo pisali v našo skripto. Torej če na pamet vemo kaj moramo storiti, nam ni treba pisati nove skripte, enostavno poženemo kar imamo v mislih. To je praktično pri enkratnih opravilih, pri večkratni rabi pa so skripte/aliasi bolj praktični (če ukazov ni več v zgodovini).
Seveda bash podpira tudi for zanke in spet je kar nekaj različnih sintaks:
navaden@lynxlynxsp wesnoth $ for i in lynx Sorbus aria; do echo $i; done
lynx
Sorbus
aria
navaden@lynxlynxsp wesnoth $ for i in {1..10}; do echo -n "$i "; done; echo
1 2 3 4 5 6 7 8 9 10
navaden@lynxlynxsp wesnoth $
|
Zdaj pa bolj praktičen primer. V $PWD imam nekaj nepotrebnih varnostnih kopij datotek. To so vse te:
navaden@lynxlynxsp wesnoth $ ls *~ enote~ less~ newwiki~ skwiki~ trfact~ updateCVS.sh~ weseder~ wiki2~* |
Rad bi jih izbrisal. Obstaja mnogo načinov:
1. ls *~ | rm #ne bo delal, ker rm hoče vsak parameter posebej
2. ls *~ | xargs rm # kar xargs popravi, toda:
navaden@lynxlynxsp wesnoth $ ls *~ | xargs rm rm: cannot remove `wiki2~*': No such file or directory |
Res je, te datoteke ni. Zakaj jo je potem poskušal zbrisati? Kriv je `ls`, ker uporabljam -F možnost, je dodal na koncu '*', kar pomeni da je datoteka izvršljiva. `rm` dobi cel niz in misli da je ime datoteke. Rešitev je, da izvedem unalias ls, ali pa da to izvršim v skripti. V njih aliasi privzeto ne delajo!
3. s for zanko:
navaden@lynxlynxsp wesnoth $ for zrtev in *~ > do > rm $zrtev > done |
globbing bo iz *~ naredil seznam vseh ujemajočih datotek in bash bo za vsako izvedel kar je med 'do' in 'done'.
4. find:
navaden@lynxlynxsp wesnoth $ find -name "*~" -maxdepth 1 -exec rm {} \;
|
Možnost -maxdepth sem uporabil, zato da je iskal samo po trenutnem imeniku in ne tudi globje.
5. Ali pa čisto preprosto:
navaden@lynxlynxsp wesnoth $ rm *~ navaden@lynxlynxsp wesnoth $ ls *~ ls: *~: No such file or directory |
Zanimiva konstrukta sta še AND (&&) in OR (||) seznama:
navaden@lynxlynxsp wesnoth $ echo popocatepetl && echo uspelo nama je, hura! popocatepetl uspelo nama je, hura! navaden@lynxlynxsp wesnoth $ echo popocatepetl || echo uspelo nama je, hura! popocatepetl navaden@lynxlynxsp wesnoth $ ls --koleraba && echo uspelo nama je, kura! ls: unrecognized option `--koleraba' Try `ls --help' for more information. navaden@lynxlynxsp wesnoth $ ls --koleraba || echo uspelo nama je, kura! ls: unrecognized option `--koleraba' Try `ls --help' for more information. uspelo nama je, kura! |
AND seznam se bo izvršil, če bo prejšnji ukaz uspešen (exit status 0), OR pa obratno, če exit status ne bo 0. `echo` je težko onesposobit, zato se lahko zanesete da bo vedno uspešno končal. `ls` je pa kapituliral, ker sem mu podal neznano stikalo.
Še en primer z indijanci:
navaden@lynxlynxsp wesnoth $ httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd || httpd |
Tako se bo `httpd` ponovno zagnal, če se slučajno sesuje. Po šestindvajstem bi pa dokončno umrl. Seveda bi lahko v seznam dodali še več členov.
Dobro branje za tiste, ki jih zanima skriptiranje je: http://tille.soti.org/training/bash/index.html
Za napredne uporabnike pa abs, bashistična biblija: http://www.tldp.org/LDP/abs/html/
[14] ob večjih potrebah si oglejte `at` in `cron`
[15] prva vrstica skripte je izjema, ki pove bashu s čim naj si razlaga sledečo skripto
ZAKLJUČEK IN VIRI MODROSTI
Vsi opisani programi imajo še mnogo drugih (z)možnosti. Če vas zanima karkoli v zvezi z njimi, si preberite njihov priročnik (manual) z `man <imeprograma>`. Končate s pritiskom na 'q', iščete pa tako da prvo pritisnete '/' in potem vnesete še iskalni niz. Nekateri programi imajo še info strani, ki vsebujejo še več podatkov (`info info`).
Če želite kaj zvedeti o nečem, pa ne veste pravega imena man strani, si še vedno lahko pomagate z man:
navaden@lynxlynxsp wesnoth $ man -k optic fiberlamp (1) - Fiber Optic Lamp fiberlamp (1) - Fiber Optic Lamp fiberlamp (1) - Fiber Optic Lamp |
Namesto optic preprosto vnesete tematiko in prefiltrirate rezultate.
Če ukaz nima man strani, poskusite s `program --help`.
Ko še to ni dovolj, se obrnite na širni internet. Po njem se valja ogromno dokumentacije in na miljone rešenih problemov.
Če pa ste se res potrudili, a vseeno ničesar našli ali rezultatov niste razumeli, se obrnite na kak forum, recimo na http://linux.prinas.si .
Eric Raymond je lepo opisal problematiko samopomoč/pomoč, oglejte si http://www.catb.org/~esr/faqs/smart-questions.html#rtfm (oglejte si tudi kazalo, ker vem da nihče ne bo bral celega howtoja)
No, to je to. Veselo tipkanje. :)
Če se vam zdi da v vodiču kaj hudo manjka ali pa če najdete kako napako/nejasnost, mi pošljite mail na `echo jaaakkkaakrrranjjjc@emaaailll...si | tr -s [.yakrlj]`, da lahko popravim original.
DODATEK
ad IMENA DATOTEK
Še ena pomembna zadeva glede imen datotek je ostala. Imena lahko vsebujejo poljubne znake, le '/' ne. Program vam bo že pojamral v takem primeru, problem nastopi pri uporabi tabulatorja in interpretaciji. Dva primera:
1. datoteke, katerih imena se začnejo s '-' bodo programom delale težave, saj bodo mislil da gre za možnosti in ne za parameter. To se reši, tako da vmes vtaknete ' -- ', kar programu pove da naj preneha iskati možnosti.
navaden@lynxlynxsp wesnoth $ ls -lh -asd 512 drwxr-xr-x 4 navaden users 768 Aug 15 19:12 ./ navaden@lynxlynxsp wesnoth $ ls -lh -- -asd -rw-r--r-- 1 navaden users 0 Aug 15 19:12 -asd navaden@lynxlynxsp wesnoth $ ls -lhasd 512 drwxr-xr-x 4 navaden users 768 Aug 15 19:14 ./ |
ls ima toliko možnosti, da se sploh ni pritožil - očitno so a, s in d vse možnosti. Samo drugi izpis je pravilen, prvi in tretji sta povsem enaka.
2. datoteke, katerih imena vsebujejo presledke, narekovaje, backticks (`), ampersand (&), klicaje, znake za manjše/večje (<,>) in najbrž še kaj drugega, bodo programom delale težave.
V primeru presledka ne bo problemov, če uporabljate tabulator. Dajte ga. Ta bo avtomatsko "ubežal" presledke (escape sequence - ubežno zaporedje; znak '\').
navaden@lynxlynxsp wesnoth $ ls aaaaaasdsasa en presledek newwiki3 /.../ navaden@lynxlynxsp wesnoth $ ls en<tab> enote enote~ en presledek navaden@lynxlynxsp wesnoth $ ls en <tab> aaaaaasdsasa newwiki tempOrarye /../ # spet pokaže vse, isto kot prvi ls navaden@lynxlynxsp wesnoth $ ls en presledek #ročno napisano ls: en: No such file or directory ls: presledek: No such file or directory |
Vidite, če sami dodamo presledek, se bo ujemanje končalo, ls bo mislil da ima opravka z več datotekami (en in karkoli še napišemo) in nobene ne bo našel, ker ne obstajajo. Potrebno je vpisati `ls en\ ` in potem lahko spet nadaljujemo s <tab>. Tu nismo imeli sreče, ker se možne razširitve ločijo ravno na mestu kjer je presledek (do 'en' so enake), drugače bi tabulator avtomatsko poskrbel za to.
Torej, v večini primerov bo pomagal '\'.
Kot alternativo lahko uporabite narekovaje - vanje dajte celo ime datoteke, recimo `ls 'en presledek'`. Priporočam enojne, ker so bolj učinkoviti.
No narekovaji bodo delali z imeni, ki vsebujejo '<' ali '>', medtem ko ubežno zaporedje (\>) ne bo.
Linux ne pozna končnic v takem smislu kot Okna. Ime je lahko kakršnokoli, nobenih pik in akronimov ni treba tlačiti zraven. Ni treba, olajša pa delo - linux bo že sam prepoznal tip datoteke iz zaglavja (po mime tipu), vi pa tega ne morete. Če se spomnite primerov, je tudi dosti lažje upravljati z datotekami s "končnicami", ker jih lahko uporabimo v vzorcih globbing.
Tu pa lahko vidite pošast po imenu sed, ki jo uporabljam za ustvarjanje tega vodiča.
http://lynxlynx.info/PBsed