Praktični Bash


Kazalo:


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:

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:

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/`

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.


[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:

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".

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



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.


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



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:

`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:

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



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.


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