Sunteți pe pagina 1din 197

Cuvânt înainte

Având o istorie de peste 30 de ani, sistemul de operare UNIX s-a


impus pe piaţa sistemelor de operare de reţea ca un sistem robust, fiabil,
portabil, capabil să ruleze pe cele mai variate arhitecturi hardware.
Conform opiniilor specialiştilor în domeniu, UNIX reprezintă sistemul de
operare original. De fapt, Microsoft Windows şi MacOS (sistemul de
operare ce rulează pe Macintosh) au fost iniţial dezvoltate ca alternative la
UNIX şi nu invers.
Cu toate că majoritatea PC-urilor actuale utilizează Windows, în
ultimul timp se observă o tendinţă din ce în ce mai puternică spre utilizarea
Linux-ului (care nu este altceva decât o variantă de UNIX) care are un
mare avantaj: este gratis! De asemenea, ultimele tipuri de interfeţe grafice
precum CDE (Common Desktop Environment), GNOME, KDE facilitează
folosirea UNIX-ului pentru utilizatorii care nu sunt specialişti în domeniul
calculatoarelor.
Pe de altă parte, cunoştinţele legate de UNIX pot reprezenta o avere
deosebită în lumea de astăzi a tehnologiei informaţiei. Multe dintre cele mai
puternice reţele din lume şi site-uri Internet sunt bazate pe UNIX, existând o
cerere deosebită pentru profesionişti specializaţi în administrarea
sistemelor UNIX. Aceşti administratori de sisteme (cunoscuţi şi sub
denumirea de sysadmin) sunt printre cei mai bine plătiţi oameni din
domeniul IT.
În primul capitol al lucrării de faţă sunt prezentate caracteristicile
generale ale sistemului de operare UNIX, istoric, tipuri de implementări,
documentare, comenzi şi interfeţe grafice.
În capitolul al doilea sunt prezentate noţiuni legate de sistemul de
fişiere UNIX precum şi comenzi referitoare la fişiere şi directoare.
Capitolul al treilea se referă la administrarea fişierelor, comenzi
legate de partiţii şi hard-disc-uri, căutarea şi sortarea fişierelor, arhivarea
şi compresia fişierelor.
În capitolul al patrulea sunt prezentate serviciile de reţea oferite în
UNIX, serviciile ARPA precum şi posibilitatea integrării cu alte sisteme de
operare.
Capitolul al cincilea face referire la editoare de texte utilizate pe
sisteme UNIX; sunt prezentate aici editorul vi şi editorul pico.
În capitolul al şaselea sunt prezentate noţiuni generale legate de
shell-uri UNIX, variante, procese UNIX şi mediul de lucru.
5
Capitolele şapte şi opt se referă la variantele Bourne Shell (sh),
respectiv Bourne Again Shell (bash). Aici sunt prezentate: gramatica Shell,
tipuri de operatori, mediul Shell, comenzi, funcţii, toate acestea însoţite de
numeroase exemple.
Obiectivul urmărit prin scrierea acestei lucrări a fost acela de a face
o introducere în lumea UNIX prezentând caracteristicile fundamentale şi
facilităţile acestui sistem de operare precum şi acela de a oferi numeroase
exemple de utilizare a programelor de tip shell-script, cu accent pe shell-ul
Bourne şi shell-ul Bourne Again.
Lucrarea se adresează în special studenţilor ce studiază sistemul de
operare UNIX în cadrul activităţilor de curs, seminar sau laborator, iar
exemplele prezentate în carte constituie o bogată sursă de inspiraţie pentru
aceştia.

Autorul

6
1 UNIX
CARACTERISTICI GENERALE

1.1 Introducere

Sistemul de operare UNIX, împreună cu suita de protocoale TCP/IP


pentru comunicaţia în reţea şi cu sistemul de fişiere NFS constituie o soluţie
convenabilă pentru constituirea unui sistem complet de operare în reţea.
Dezvoltat iniţial în laboratoarele AT&T Bell Labs (cu participarea
companiei General Electric şi a faimosului MIT – Massachusetts Institute of
Technology), UNIX-ul reprezintă, de fapt, o mare familie de sisteme de
operare înrudite ce descind din munca programatorilor Dennis Ritchie şi
Ken Thompson (creatorii limbajului C) la sfârşitul anilor 60 şi începutul
anilor 70. Sistemele din familia UNIX pot fi rulate pe orice tip de calculator,
plecând de la calculatoarele personale până la super-calculatoarele cu
configuraţii extrem de avansate, utilizate îndeosebi în domeniul militar şi cel
bancar. De asemenea, toate variantele de UNIX sunt multitasking•, domeniu
în care UNIX are o reputaţie deosebită.
Numele său derivă de la un jos de cuvinte al unui alt proiect
Bell Labs/MIT din acelaşi timp produs pe un calculator mainframe cunoscut
sub numele de Multics (Multiplexed Information and Computing Service).
Sistemul de operare interactiv Multics fusese scris pentru un computer al
companiei General Electric dovedindu-se după ani de dezvoltare mult prea
costisitor, de aceea Bell Labs s-a retras ulterior din proiect.
În timpul lucrului la proiectul Multics, programatorul
Ken Thompson a scris un joc de călătorie în spaţiu pentru computerul
General Electric. După sistarea proiectului, acesta a rescris jocul împreună


Prin multitasking se înţelege capacitatea unui sistem de operare de a executa mai multe
procese (task-uri) simultan. Acest lucru se realizează prin fenomenul „time slicing” ce
presupune că fiecare proces aflat în execuţie utilizează calculatorul pentru o perioadă
determinată de timp. Comportamentul multitasking este în opoziţie cu „task switching”,
caz în care fiecare proces aflat în execuţie trebuie să se termine pentru a se începe
execuţia unui nou proces.

7
UNIX

cu colegul său Dennis Ritchie pentru a rula pe un computer DEC PDP-7 ce


avea un display grafic mai performant. Acest calculator avea nevoie însă de
un sistem de operare viabil. Iniţial, noul sistem de operare a fost numit de
către Thompson UNICS (Uniplexed Information and Computing Service),
apoi numele său s-a schimbat în UNIX iar jocul de călătorie spaţială a fost
modificat pentru a rula sub UNIX.
Cu toate îmbunătăţirile aduse de-a lungul timpurilor, de la primele
implementări de UNIX şi până acum, toate variaţiile sale urmăresc într-o
mare măsură arhitectura şi funcţionalitatea originală UNIX.

1.2 Scurt istoric

Pentru a înţelege mai bine caracteristicile acestui sistem de operare,


avantajele şi dezavantajele sale, este util să cunoaştem câteva lucruri legate
de istoria sa.
După cum am spus mai înainte, UNIX a fost conceput iniţial la
Bell Laboratories USA drept un proiect privat de cercetare, proiect început
în 1969 de către un mic colectiv de cercetători. Scopul acestui colectiv de
cercetare era acela de a concepe un sistem de operare care să corespundă
următoarelor exigenţe:
ƒ să fie elegant, simplu şi concis;
ƒ să fie scris într-un limbaj de programare de nivel înalt şi nu în
limbaj de asamblare;
ƒ să permită refolosirea codului.
La început, UNIX a fost scris în limbaj de asamblare şi de aceea nu
putea rula decât pe un calculator anume. Odată cu naşterea limbajului C în
1971, Ritchie şi Thompson au rescris în 1973 programele de sistem UNIX
în C. În acest fel UNIX-ul putea fi mutat (portat) şi pe alte calculatoare fără
un efort prea mare de programare. În aceeaşi perioadă, compania AT&T
(firmă mamă pentru Bell Laboratories) a fost declarată monopol de Comisia
Federală de Comerţ a SUA. Drept compensaţie, Bell Laboratories a oferit
gratis sistemul de operare UNIX universităţilor din SUA, astfel încât acesta
a devenit extrem de popular în mediul academic. Cu timpul, UNIX s-a
răspândit şi în mediul comercial, în care studenţii aplicau ceea ce au învăţat
pe băncile universităţilor.
Spre deosebire de majoritatea producătorilor de sisteme de operare
din acel timp, care produceau sisteme mari şi scrise în limbaj de asamblare,
UNIX avea un mic procent de cod scris în limbaj de asamblare (aproximativ
10% - kernelul), în timp ce restul codului era scris în C. Grupul de
dezvoltare a sistemului a conceput iniţial munca în limbaj de nivel înalt,

8
UNIX Caracteristici generale

apoi, odată cu dezvoltarea sa, au apărut mici schimbări ce au fost făcute în


kernel şi în limbajul de programare pentru a se definitiva UNIX-ul.
În cadrul acestei evoluţii continue, kernelul şi software-ul aferent au
fost extinse până când s-a creat un sistem de operare scris în C, bazat pe
kernelul în limbaj de asamblare.
Codul sursă al sistemului de operare UNIX a fost făcut public şi
disponibil universităţilor de pe întreg teritoriul SUA. Programatorii de la
Universitatea Berkeley din California au făcut modificări substanţiale
codului sursă original şi astfel s-a născut BSD (Berkeley Software
Distribution) UNIX. Această nouă versiune de UNIX a fost făcută
cunoscută la rândul ei programatorilor din SUA care au adăugat instrumente
şi cod. Cea mai importantă îmbunătăţire adusă sistemului de operare de
către programatorii de la Berkeley a fost adăugarea software-ului de reţea ce
a permis sistemului de operare să funcţioneze într-o reţea locală. Varianta
BSD UNIX a devenit extrem de populară printre producătorii de computere,
dintre care: Hewlett Packard, Digital Equipment Corporation şi Sun
Microsystems.
Scurt istoric al sistemului de operare UNIX
Tabelul 1.1
1969 – Începutul dezvoltării a ceea ce urma să devină UNIX de către programatorii
Ken Thompson şi Dennis Ritchie la Bell Laboratories.
1973 – UNIX este rescris în C pentru a fi portabil şi a putea rula pe diverse computere.
1975 – Se distribuie versiunea 6 în afara laboratoarelor Bell; prima versiune BSD derivă
din această versiune V6.
1980 – Microsoft produce Xenix iar BSD 4.2 este larg utilizat.
1984 – Universitatea Berkeley din California distribuie versiunea 4.2 BSD ce include suita
de protocoale TCP/IP pentru reţea şi alte programe aplicative.
1984 – Apare versiunea SVR2 (System V Release 2); există aproximativ 100.000 de
instalări de UNIX în întreaga lume.
1986 – Apare versiunea 4.3BSD ce include internet name server.
1987 – Apare versiunea SVR3; în acest moment există aproximativ 750.000 de instalări de
UNIX în întreaga lume.
1988 – Apare UNIX SVR4 prin unificarea versiunilor System V, BSD şi Xenix.
1991 – UNIX System Laboratories (USL) devine o companie în care acţionar majoritar este
AT&T; Linus Torvalds începe dezvoltarea Linux-ului.
1992 – USL elaborează UNIX SVR4.2 iar Novell îşi anunţă intenţia de a prelua USL.
1993 – Apare versiunea 4.4BSD de la Berkeley. Novell preia USL.
1999 – UNIX împlineşte 30 de ani; kernel-ul Linux ajunge la versiunea 2.2.
2001 – Versiunea 3 Single UNIX Specifications reuneşte eforturile POSIX, The Open
Group şi ale altor companii. Kernel-ul Linux ajunge la varianta 2.4
2003 – Kernel-ul Linux ajunge la versiunea 2.5
2004 – Se află în lucru variante ale kernel-ului Linux versiunea 2.6

9
UNIX

În timp ce firma Sun Microsystems avea sistemul de operare SunOS


bazat pe versiunea BSD UNIX 4.2, compania AT&T folosea o versiune de
UNIX cunoscută sub numele de System V (system five). În anul 1988,
SunOS/BSD, AT&T System V Release 3 şi XENIX (o versiune de UNIX
dezvoltată de Microsoft pentru PC-uri cu procesoare Intel) au fost
combinate într-o nouă versiune UNIX denumită System V Release 4
(SVR4). Această nouă generaţie a sistemului de operare UNIX a fost creată
în scopul combinării celor mai bune caracteristici din varianta BSD cât şi
din varianta AT&T System V pentru a crea un standard în industria
sistemelor de operare. Acest lucru a permis dezvoltarea de software pentru
UNIX indiferent că era vorba despre System V sau BSD 4.2. Noua variantă
SVR4 a devenit baza celor mai multe varietăţi de UNIX.
În tabelul 1.1 regăsim istoria de peste 30 de ani a sistemului de
operare UNIX.

1.3 UNIX – sistem de operare pentru reţea

Ca un vechi şi adevărat sistem de operare pentru reţea, UNIX oferă


facilităţi avansate în acest sens, printre care:

ƒ Operare multi-utilizator
ƒ Multitasking
ƒ Procesare distribuită
ƒ Nivel ridicat de securitate

Facilitatea de operare multi-utilizator permite accesul simultan la


sistem pentru mai mulţi utilizatori ce pot astfel partaja aceleaşi resurse ale
sistemului. Sistemul de operare are grijă de fiecare resursă a computerului,
fie că este vorba de memoria RAM, microprocesor, hard disk, scanner sau
imprimantă, permiţând partajarea fiecăreia dintre acestea. Fiecare program
aflat în execuţie poartă numele de proces sau task. Sistemul de operare
UNIX ţine evidenţa mai multor procese simultan – această capacitate a sa
este denumită multitasking. Acest fapt permite mai multor aplicaţii să ruleze
în acelaşi timp pe computer.
De asemenea, capacitatea de procesare distribuită a sistemului de
operare se referă la faptul că acesta permite utilizarea partajată a resurselor
în cadrul reţelei. Cel mai simplu exemplu în acest sens este acela în care un
utilizator poate accesa fişiere şi aplicaţii de pe hard disk-ul altui computer
situat în altă parte a reţelei de calculatoare.

10
UNIX Caracteristici generale

În fine, sistemele de operare pentru reţea au implementate sisteme de


securitate foarte sigure; există multe alte facilităţi de asigurare a securităţii
în afară de cea clasică nume-de-utilizator/parolă. De regulă, facilităţile de
asigurare a securităţii sistemului pot fi active sau nu, în funcţie de politicile
de securitate implementate la nivelul companiei respective.

1.4 Arhitectura UNIX

Sistemul de operare UNIX este un sistem de operare structurat în


principal pe următoarele două nivele:

ƒ Programe sistem UNIX;


ƒ Nucleul (denumit kernel) sistemului UNIX.
Majoritatea programelor sistem şi kernel sunt scrise în C, permiţând
portabilitatea pe alte platforme hardware ce posedă un compilator C.
Programele de sistem UNIX oferă funcţionalitatea cerută de utilizatori prin
iniţierea unui sistem de apeluri către nucleul sistemului UNIX. Nucleul
îndeplineşte aceste cereri interacţionând cu nivelul hardware şi returnând
rezultatele scontate utilitarelor şi programelor sistem. În această arhitectură
stratificată, doar nucleul UNIX trebuie să se ocupe de echipamentele
hardware specifice cu care trebuie să interacţioneze; în interiorul nucleului
majoritatea codului specific hardware se limitează la driverele
echipamentelor.
Nucleul reprezintă centrul sistemului de operare şi are rolul de a
oferi funcţionalităţile de bază necesare funcţionării computerului. Nucleul
este apropiat de microprocesor şi hardware, fiind un fişier executabil ce este
încărcat în memorie atunci când are loc procesul de boot al calculatorului,
fiind denumit generic unix (pe sistemele bazate pe System V) sau vmunix
(pe sistemele bazate pe BSD). Odată cu încărcarea în memorie, nucleul
începe execuţia următoarelor funcţii:
ƒ Administrarea echipamentelor, a memoriei şi a proceselor;
ƒ Asigură controlul funcţiilor de transmisie a informaţiilor între
programele de sistem şi echipamentele hardware;
ƒ Administrează entităţi precum spaţiul de swap, demonii şi
sistemul de fişiere.
Spaţiul de swap reprezintă o porţiune specială de pe
hard-disc ce este folosit de către kernel pentru procesare.
Bucăţi ale programelor ce se află în execuţie pot fi
interschimbate între memoria RAM şi hard-disc ori de câte
ori este nevoie. Acest mecanism de extindere a memoriei

11
UNIX

RAM a sistemului prin utilizarea spaţiului de pe hard-disc


poartă denumirea de memorie virtuală.
Demonii sunt programe (sau procese) ce îndeplinesc un anumit
rol; ei sunt procese speciale care îşi încep execuţia după
încărcarea sistemului de operare în memorie. După aceea,
demonii aşteaptă să ruleze anumite sarcini în sprijinul
sistemului de operare, putând fi porniţi manual sau în mod
automat. Un exemplu de proces demon este dtlogin care
determină apariţia ecranului de login CDE la începutul unei
sesiuni UNIX sau după ce utilizatorul iese din File Manager-ul
CDE. Procesele demon din lumea UNIX sunt similare cu
serviciile (services) din Windows NT/2000/XP sau cu modulele
NLM (Netware Loadable Modules) din sistemul de operare
Novell Netware.
Sistemele de fişiere reprezintă modalitatea de organizare a
directoarelor, subdirectoarelor, fişierelor pe hard-disc.
Sistemele de fişiere pot fi situate atât local (pe calculatorul
local) cât şi la distanţă (pe alt calculator din reţea, de regulă
un aşa numit server).

Programele şi utilitarele sistemului, precum şi aplicaţiile


utilizatorilor sunt independente de hardware şi singura cerinţă pentru acestea
este să iniţieze apeluri standardizate de sistem către nucleul UNIX. Cele mai
multe dintre funcţiile nucleului UNIX se ocupă de managementul fişierelor
sau al anumitor tipuri de dispozitive. Pentru a simplifica şi standardiza
apelurile de sistem, UNIX interpretează echipamentele ca fiind tipuri
speciale de fişiere. Poate cea mai importantă caracteristică a sistemului
UNIX este aceea a disponibilităţii codului sursă, ceea ce permite multor
programatori să îmbunătăţească şi să modifice aceste sistem de operare de-a
lungul anilor. Cele două proprietăţi remarcabile ale sistemului de operare
UNIX sunt:
ƒ Portabilitatea – aceasta se manifestă în două moduri: în primul
rând, UNIX este portabil pe numeroase platforme hardware; în al doilea
rând, programele scrise pentru UNIX sunt implicit portabile pe toate
platformele UNIX, depinzând de nivelul de similaritate între nucleele şi
programele de sistem UNIX;
ƒ Modularitatea – UNIX este un sistem dinamic, a cărui
funcţionalitate poate fi îmbunătăţită prin adăugarea de noi programe
utilitare; de asemenea, este posibilă şi modificarea nucleului şi recompilarea
sa pentru un sistem de operare mai bun.
12
UNIX Caracteristici generale

Arhitectura generală şi cele mai importante funcţii ale nucleului


UNIX sunt prezentate în figura 1.2.

Figura 1.2 Arhitectura generală a sistemului de operare UNIX

1.5 Funcţionalităţi UNIX

Dintre cele mai importante caracteristici funcţionale ale sistemului


de operare UNIX se disting următoarele:
ƒ Operare multiutilizator;
ƒ Multitasking preemtiv;
ƒ Multiprocesare;
ƒ Suport pentru aplicaţii multi-threaded.
O altă caracteristică importantă este aceea a managementului
memoriei care este realizat prin două metode de bază: memoria virtuală
(prin procedeul de swapping) şi paginarea. Prima metodă permite
interschimbarea proceselor între memoria fizică şi partiţia de swap de pe
hard disc, în timp ce procedeul de paginare caută să elimine sau cel puţin să
minimizeze fragmentarea (care apare în procesul de swapping), permiţând
astfel proceselor să execute doar acele porţiuni ale acestora care sunt
prezente în memoria principală. Aceste porţiuni de dimensiune fixă
încărcate în memoria principală la cerere sunt cunoscute sub denumirea de
pagini, iar întregul proces este referit sub numele de sistemul de memorie
virtuală (bazat pe cereri de pagini).

13
UNIX

Altă funcţionalitate de bază este aceea oferită de sistemul de


intrare/ieşire care încearcă să minimizeze interacţiunile (specifice
hardware) necesitate de nucleul UNIX. Sistemul de intrare/ieşire al
sistemului de operare UNIX este alcătuit din:

ƒ Interfaţa socket, folosită pentru comunicaţiile între procese;


ƒ Driverul dispozitivelor bloc, folosit pentru comunicarea cu
dispozitive orientate pe bloc (de exemplu hard discuri sau unităţi
de bandă). Transferurile efectuate de astfel de dispozitive se fac
de regulă în blocuri de lungime fixă de 512 sau 1024 octeţi;
ƒ Driverul dispozitivelor orientate caracter, folosite pentru
comunicarea cu dispozitivelor orientate pe caracter (terminale,
imprimante sau alte dispozitive care nu transferă date în blocuri
de octeţi de dimensiune fixă).

În fine, un rol de bază în funcţionarea sistemului UNIX îl are


controlul proceselor şi intercomunicarea între procese (asigurată prin
mecanismul de conductă –pipe- fie prin sockets).

1.6 Implementări de UNIX

Două dintre familiile importante ale sistemului de operare UNIX


sunt:

ƒ UNIX System V Release 4, cunoscut de regulă sub denumirea


de SVR4 sau V.4, derivă din modelul original dezvoltat la
Bell Laboratories, cunoscut mai târziu sub numele de UNIX
Systems Laboratory (USL) şi vândut apoi către SCO (Santa Cruz
Operation) şi
ƒ Berkeley Software Distribution (BSD) versiunea 4.4., variantă
cunoscută sub denumirea de 4.4BSD.

Există însă o mare varietate de sisteme de operare UNIX, majoritatea


acestora fiind similare deoarece sunt bazate pe standardul SVR4. Celelalte
varietăţi sunt bazate pe BSD. Cele mai multe diferenţe apar la comenzile de
administrare a sistemului. Putem spune dacă lucrăm pe un sistem de operare
bazat pe System V sau BSD şi după comenzile de printare (lp pentru System
V şi lpr pentru BSD) şi de vizualizare a proceselor lansate în execuţie
(ps –ef pentru System V şi ps –aux pentru BSD).

14
UNIX Caracteristici generale

UNIX a devenit o marcă înregistrată (deţinută de The Open Group –


www.opengroup.org), de aceea fiecare producător de UNIX şi-a ales
propriul nume. Spre exemplu, versiunea de UNIX a firmei Sun se numeşte
Solaris, a firmei IBM se numeşte AIX iar a firmei Hewlett Packard se
intitulează HP-UX.
În tabelul 1.3 sunt prezentate o serie de implementări UNIX,
platformele hardware pe care acestea activează precum şi vânzătorii
produselor.

Diferite implementări de UNIX

Tabelul 1.2
Implementarea
Platforma hardware Vânzător
UNIX

A/UX Macintosh Apple Computer

AIX Staţii şi mainframe-uri IBM, IBM


RS/6000

HP-UX Staţii HP RISC Hewlett-Packard


Corporation

Linux Intel x86 Shareware

NextStep Intel 486 sau Pentium, Next Next Computer

OSF/1 şi Ultrix Staţii DEC VAX şi Alpha Digital Equipment


Corporation

SCO OpenServer Intel 486 sau Pentium Santa Cruz Operation

Solaris Staţii Sun Sparc şi Intel x86 SunSoft

UNIXWare Intel 486 sau Pentium Novell

Aceste variante de UNIX sunt concepute să ruleze pe platformele


hardware specifice firmelor care le-au dezvoltat. Unele variante însă rulează
pe mai multe platforme hardware; spre exemplu, Solaris rulează atât pe staţii
de lucru Sun cât şi pe staţii cu microprocesoare Intel şi până la computere de
tip mainframe şi supercomputere.
Ultimul sistem de operare derivat din kernelul UNIX îl reprezintă
Linux-ul, conceput să ruleze pe microprocesorul Intel de la staţii de lucru
ieftine (chiar şi 386!) până la servere performante. Linux-ul a devenit foarte
popular printre specialiştii entuziaşti ai computerelor în necesitatea găsirii
unui sistem de operare stabil şi ieftin.

15
UNIX

Totul a plecat în 1992 de la Linus Torvalds de la Universitatea din


Helsinki, Finlanda, care a făcut public Linux-ul pe Internet şi a încurajat pe
toată lumea să contribuie la dezvoltarea sa. În mod periodic un grup de
dezvoltatori revizuiesc şi testează ultimile contribuţii şi elaborează
o versiune stabilă a sistemulului de operare. Linux este gratis conform GNU
General Public Licence (www.gnu.org) dar există o serie de companii care
adaugă sistemului produse de tip Office, interfeţe desktop, software pentru
Web server, etc. precum şi CD-uri de instalare şi percep astfel o taxă (care
este, oricum, mult mai mică decât a oricărui alt sistem de operare
comercial).

1.7 GNU Not UNIX, free software şi open source

Conceptul de „free software” este un concept vechi; primele


calculatoare personale au ajuns prima dată în universităţi, fiind instrumente
de cercetare. Software-ul putea fi instalat în mod liber pe orice calculator,
iar programatorii (puţini, la acea vreme) erau plătiţi pentru activitatea de
programare, nu pentru programele în sine pe care le realizau. Ceva mai
târziu însă, atunci când calculatoarele personale au intrat în lumea afacerilor,
programatorii au început să restricţioneze drepturile de folosire a software-
ului pe care îl produceau, percepând taxe de utilizare pentru copiile
programelor.
Numele de GNU provine de la sintagma „GNU Not UNIX” şi s-a
dorit a fi un sistem de operare precum UNIX ce este distribuit cu codul
sursă şi poate fi copiat, modificat şi redistribuit. Proiectul GNU a fost iniţiat
în 1983 de Richard Stallman şi alţii ce au pus bazele Fundaţiei pentru
Software Liber (FSF – Free Software Foundation). Concepţia lui Stallman
este aceea că utilizatorii pot face ce doresc cu software-ul achiziţionat,
putând face cópii ale acestuia pentru prieteni şi modifica codul sursă
redistribuind-ul la un anumit cost. FSF stipulează termenul copyleft care
înseamnă că oricine redistribuie software free trebuie să lase în continuare
libertatea de copiere şi redistribuţie a programului, asigurându-se în acest fel
că nimeni nu va reclama drepturi de proprietate asupra unor versiuni viitoare
şi nu va impune restricţii la utilizarea acestuia.
În acest context, termenul free înseamnă libertate şi nu neapărat
gratis. Fundaţia FSF percepe nişte costuri iniţiale la distribuţia GNU.
Redistribuitorii pot, de asemenea, să perceapă taxe pentru copiile
programelor în scopul profitului sau pentru acoperirea costurilor. Ideea de
bază a software-ului liber (free software) este aceea că se lasă libertatea

16
UNIX Caracteristici generale

utilizatorilor să modifice şi să reasambleze produsul fără nici o restricţie în


afară de aceea că nici ei, la rândul lor, nu pot impune restricţii mai departe.
Stallman crede că unul dintre rezultatele filozofiei free software este
acela că mai multe programe free vor coexista împreună provenind din alte
programe free. GNU• este un exemplu în acest sens; acesta a devenit un
sistem de operare când în august 1996 i-a fost adăugat un kernel (GNU
Hurd şi Mach). Fundaţia FSF continuă să dezvolte software free sub formă
de programe de aplicaţii; un program de tip spreadsheet este acum
disponibil. Sistemul de operare Linux este conceput cu componente GNU
iar kernelul este dezvoltat de Linus Torvalds.
Munca lui Stallman a inspirat multe contribuţii de software free, iar
definiţia open source conţine multe dintre ideile lui Stallman, putând fi
considerată drept un concept derivat. Open Source Definition a luat naştere
odată cu distribuţia Debian GNU/Linux. Sistemul de operare Debian, o
variantă de Linux populară şi în zilele noastre, a fost construit în întregime
pe bază de software free. Cu toate acestea, deoarece avea alte licenţe diferite
de copyleft (care era prin definiţie free), Debian a avut ceva probleme în
definirea faptului că este free. Cu timpul au fost elaborate o serie de reguli
definite în “Debian Free Software Guidelines”, document ce defineşte
practic software-ul open source.
Partizan împătimit al software-ului free, Eric Raymond a scris un
articol intitulat „The Cathedral and the Bazaar” (Catedrala şi bazarul) în
încercarea de a explica ideea de free software. În acest articol, Raymond
descrie software-ul comercial ca fiind dezvoltat în stilul unei catedrale,
izolat de marea majoritate a dezvoltatorilor independenţi, în timp de
software-ul free se construieşte în stil de bazar, oferind un loc de întâlnire
pentru oricine doreşte acest lucru. În articol se susţine ideea că “modelul de
bazar” este superior deoarece un număr mult mai mare de utilizatori şi
programatori contribuie la dezvoltarea de software mai bun şi într-un timp
mai scurt. Toţi cei care doresc să contribuie la scrierea codului pentru
proiect sunt bineveniţi, iar cel mai bun cod va fi ales pentru includerea în
proiectul final.


GNU s-a vrut iniţial să fie o alternativă la versiunile comerciale de UNIX. Acest lucru nu
s-a întâmplat încă, dar Richard Stallman şi alţi programatori muncesc în continuare pentru
acest ideal. Paradoxal este că primele succese înregistrate de GNU au fost aplicaţii
adiţionale sistemelor proprietare UNIX. Componente GNU precum GNU Emacs, GCC
(GNU C Compiler) şi bash (un înlocuitor free pentru Bourne Shell) sunt instalate astăzi
implicit pe majoritatea variantelor de UNIX existente.

17
UNIX

Articolul „The Cathedral and the Bazaar” a avut un mare succes şi o


mare influenţă ulterior: oficialii de la Netscape au dezvăluit codul sursă al
vestitului lor browser web (Netscape Navigator) în speranţa că dezvoltatori
independenţi îl vor face mai bun. Mai mult, Netscape a început să îl consulte
pe Raymond cu privire la integrarea firmei în curentul free software. La
începutul anului 1998, Eric Raymond s-a întâlnit cu o serie de susţinători ai
conceptului de free software pentru a discuta modalităţi prin care să
încurajeze şi alte companii precum Netscape să li se alăture. Printre ideile
vehiculate atunci, s-a stabilit că termenul free (care în engleză are un sens
dual, de liber, dar şi de gratis) sună anti-comercial, drept pentru care au
propus termenul de open source drept înlocuitor. Netscape a folosit
termenul de open software atunci când a anunţat distribuirea publică a
codului sursă pentru Netscape Navigator iar faimoasa editură O’Reilly and
Associates a adoptat acest termen în materialele sale promoţionale. Cu
ajutorul acestor două mari firme, termenul de open source a început să aibă
mare succes.
Similar cu acest concept a luat naştere şi ideea de „open hardware”
cu privire la dispozitivele şi interfeţele hardware. Acest concept însă nu a
avut acelaşi succes ca ideea de software open source, dar el încă există şi
poate fi studiat la adresa web http://www.openhardware.org/.

1.8 Comenzi şi interfeţe grafice în UNIX

Sistemul de operare UNIX posedă peste 350 de comenzi de sistem şi


programe utilitare folosite pentru administrarea sistemului (adăugare de noi
utilizatori, noi dispozitive hardware, etc.), administrarea sistemului de
fişiere (creare, editare, copiere, ştergere, printare, etc.), asigurarea
conexiunii la reţea şi comunicării cu alte sisteme şi oferirea de ajutor.
Interpretorul de comenzi (shell-ul) preia comenzile şi le execută. Unele
dintre comenzi sunt înglobate în interpretor, precum comanda cd (change
directory) dar marea majoritate a comenzilor se află pe hard-disc, de regulă
în directoare specifice, precum directorul bin (prescurtarea de la binary
code).
Toate sistemele de operare moderne au un sistem grafic de interfaţă
cu utilizatorul (GUI – Graphical User Interface); interfaţa grafică
Macintosh, Microsoft Windows sau UNIX CDE sunt exemple de astfel de
interfeţe.

18
UNIX Caracteristici generale

Interfaţa grafică CDE (Common Desktop Environment)

Firma Sun Microsystems a fost una dintre primele firme ce a utilizat


o interfaţă grafică pentru sistemul de operare UNIX. În anul 1993 s-a format
un consorţiu de firme ce comercializau sisteme de operare UNIX, cu scopul
de a dezvolta un mediu de interfaţă grafică, integrat, standard şi funcţional.
Printre membrii acestui consorţiu se numărau: Hewlett-Packard, IBM,
Novell, Sun Microsystems, companii şi membri ai fundaţiilor OSF (open
Software Foundation), X/Open şi X Consortium. CDE este bazat
pe standardul Motif, oferind o serie de caracteristici generale, comune cu
alte medii desktop, printre care:
ƒ oferă un mediu GUI de interfaţă între utilizator şi sistemul de
operare;
ƒ include meniuri ce pot fi selectate de către utilizatori şi permite
rularea unor programe fără a fi necesară scrierea comenzii la
linia de comandă;
ƒ oferă peste 300 de programe utilitare şi instrumente;
ƒ permite utilizatorilor să controleze mai multe documente şi
aplicaţii pe ecran în acelaşi timp;
ƒ controlează activităţile din ferestre atât cu ajutorul mouse-ului
cât şi cu ajutorul tastaturii.
Ecranul CDE poate fi observat în figura 1.4, cu principalele
programe şi instrumente de lucru: calendar, administrare de fişiere, e-mail,
administrarea printării etc.

19
UNIX

Figura 1.4 Interfaţa grafică CDE

Interfaţa grafică GNOME

O altă interfaţă grafică mai recentă în lumea UNIX este GNU


Network Object Model Environment (GNOME) şi face parte din proiectul
GNU open source. GNOME (vezi figura 1.5) posedă un mediu grafic uşor
de utilizat pentru utilizator precum şi un cadru propice de dezvoltare a
aplicaţiilor – de asemenea, fiind software open source, este gratis. Interfaţa
GNOME (http://gnome.org) este inclusă în majoritatea versiunilor de UNIX
BSD precum şi în distribuţiile de GNU/Linux. De asemenea, GNOME
funcţionează şi cu Sun Solaris (http://www.sun.com/gnome). GNOME
posedă o interfaţă intuitivă, uşor de utilizat, combinând o organizare
complexă a desktop-ului cu facilităţi de navigare ce permit un acces uşor la
informaţii.

20
UNIX Caracteristici generale

Figura 1.5 Interfaţa grafică GNOME

1.9 Documentarea în UNIX

Fie că este vorba despre un începător sau despre un utilizator avansat


în utilizarea UNIX-ului, totdeauna este utilă consultarea paginilor de help
(care în UNIX se numesc pagini de manual, sau man pages). Dar să vedem
cum se poate obţine ajutor în UNIX atunci când vrem să aflăm cum se
utilizează o comandă ?
Cea mai la îndemână soluţie este consultarea paginilor de manual,
acest lucru făcându-se prin utilizarea comenzii man. A doua soluţie ar fi
utilizarea resurselor Internet. În continuare vom prezenta mai pe larg aceste
două opţiuni.

21
UNIX

1.9.1 Utilizarea comenzii man


Manualul programatorului UNIX (paginile de manual) descriu toate
detaliile pe care trebuie să le cunoaştem pentru a utiliza comenzi, a
programa sau a administra sistemul. De regulă, paginile de manual sunt
instalate automat odată cu instalarea sistemului. Paginile de manual se
prezintă sub formă de text, fără grafice, desene, etc. Pentru a accesa paginile
de manual trebuie să utilizăm comanda man la prompter. Paginile de manual
sunt deosebit de utile fie atunci când am uitat sintaxa unei comenzi sau
dorim informaţii în plus cu privire la acea comandă.
Paginile de manual oferă informaţii cu privire la sintaxa generală a
comenzii, descrierea funcţionalităţii acesteia, opţiunile şi argumentele
utilizate şi exemple de folosire a comenzii. Unele dintre comenzi nu vor
funcţiona la fel în cadrul shell-urilor diferite; în acest caz se va face referire
la shell-ul Bourne (sh), shell-ul Korn (ksh), shell-ul Bourne Again Shell
(bash) sau shell-ul C (csh).

Figura 1.6 Listing pentru comanda man ls

22
UNIX Caracteristici generale

Să vedem în continuare câteva moduri în care poate fi utilizată


comanda man:
Oferă informaţii cu privire la o comandă anume,
$ man nume unde nume este denumirea completă a comenzii
respective
În figura 1.6 avem ca exemplu o parte din listing-ul obţinut în urma
apelului comenzii man ls (informaţii cu privire la comanda ls).
O altă posibilitate de utilizare a comenzii man este aceea în care se
foloseşte o anumită secţiune din manualul UNIX, având în vedere că
paginile de manual sunt structurate pe mai multe secţiuni. Dintre aceste
secţiuni, cele mai importante sunt: secţiunea 1 - comenzi utilizator,
secţiunea 2 - apeluri de sistem, secţiunea 3 - apeluri de biblioteci.
Comenzile precum man(1) sunt grupate deci în secţiunea 1.
Oferă informaţii cu privire la o
$ man -s nr_sectiune nume comandă cu numele specificat de
nume, în secţiunea nr_sectiune

Observaţie
Această comandă poate să difere de la un sistem la altul. Modalitatea
de apel prezentată mai sus se referă la Sun Solaris. Pe un sistem FreeBSD
însă, comanda poate fi apelată în felul următor, fără a se specifica opţiunea -
s: man nr_sectiune nume.

În cazul în care nu ştim numele comenzii, putem apela comanda man


folosind opţiunea -k, prin care facem o căutare după un cuvânt cheie.
Oferă informaţii cu privire la
$ man -k cuvant_cheie comenzi referitoare la cuvântul
cheie specificat
Exemplul următor ne arată cum am putea căuta informaţii cu privire
la modificarea proprietarului (owner) unui fişier:

$ man -k owner
chown(2), fchown(2), lchown(2) - change owner and group
of a file
chown(8) - change file owner and group
$

23
UNIX

Listingul anterior conţine o serie de referinţe care conţin cuvântul


cheie owner. Pe unele sisteme UNIX acest lucru se poate face utilizând
comanda apropos, ca în exemplul următor:

$ apropos owner
chown(2), fchown(2), lchown(2) - change owner and group
of a file
chown(8) - change file owner and group
$

De asemenea, se pot afişa informaţii generale în legătură cu o


comandă specificată folosind whatis. Comanda whatis se poate folosi astfel:
Afişează linia de început din cadrul
$ whatis comanda paginii de manual referitoare la
comanda specificată
Comanda whatis poate fi utilă în cazul în care ne reamintim
comanda dar nu mai ştim la ce se foloseşte.
În mod normal, listingul obţinut în urma unei comenzi man se poate
întinde pe multe pagini. În acest sens, este util să cunoaştem câteva taste
specifice utilizate pentru navigarea în cadrul paginilor listate pe ecran. În
tabelul 1.7 sunt prezentate câteva taste folosite la navigarea prin listingul
paginilor de manual.

Taste utilizate pentru deplasarea în cadrul paginilor de manual

Tabelul 1.7
Tasta SPACE Determină defilarea ecran cu ecran
Tasta RETURN Determină defilarea unei singure linii de ecran
Tasta b Înapoi cu un ecran (b - back)
Tasta f Înainte un ecran (f - forward)
Tasta q Se încheie listarea şi comanda man (q - quit)
/sir_caractere Se caută şirul de caractere specificat
Tasta n Se caută următoarea apariţie a şirului de
caractere (n - next)
Tasta h Se afişează informaţii privind posibilităţile de
deplasare în listing (h - help)

24
UNIX Caracteristici generale

1.9.2 Utilizarea referinţelor Internet


Pe Internet există o serie întreagă de documentaţii cu privire la
sistemul de operare UNIX. În tabelul 1.8 sunt prezentate câteva adrese web
utile ce conţin astfel de documentaţii.

Resurse Internet pentru diverse variante de UNIX

Tabelul 1.8
URL Varianta de UNIX
http://www.FreeBSD.org/cgi/man.cgi BSD
http://docs.hp.com/index.html HPUX 10 & 11
http://docs.sun.com/ SunOS, Solaris
http://www.ibm.com/servers/aix/ IBM AIX
http://support.sgi.com/search/ SGI IRIX/Linux
http://doc.sco.com/ UnixWare & SCO

Dintre aceste adrese web, prima (http://www.FreeBSD.org) merită o


atenţie deosebită, deoarece prezintă pagini de manual şi pentru alte versiuni,
cum ar fi:
ƒ BSD, 2.9.1 BSD, 2.10 BSD, 2.11 BSD
ƒ BSD 0.0, 386BSD 0.1
ƒ BSD NET/2, 4.3BSD Reno, 4.4BSD Lite2
ƒ FreeBSD 1.0-RELEASE - FreeBSD 4.0-RELEASE
ƒ FreeBSD 5.0
ƒ FreeBSD Ports
ƒ Linux Slackware 3.1
ƒ Minix 2.0
ƒ NetBSD 1.2 - NetBSD 1.4
ƒ OpenBSD 2.1 - OpenBSD 2.6
ƒ Plan 9
ƒ RedHat Linux/i386 4.2, 5.0, 5.2,etc.
ƒ SunOS 4.1.3, 5.5.1, 5.6, 5.7
ƒ ULTRIX 4.2
ƒ UNIX Seventh Edition

25
2 SISTEMUL DE FIŞIERE UNIX
ŞI COMENZI

2.1 Generalităţi

Sistemul de fişiere reprezintă o construcţie logică ce oferă


posibilitatea stocării şi regăsirii informaţiei ce se află pe un dispozitiv de
stocare cu acces aleator. Un sistem de fişiere este parte integrantă a
sistemului de operare şi este format din fişiere, directoare precum şi
informaţii necesare pentru localizarea şi accesul acestora. Sistemul de fişiere
UNIX ordonează şi grupează din punct de vedere logic fişierele într-o
manieră eficientă, prin cuprinderea acestora în directoare ce sunt
asemănătoare dosarelor ce conţin mai multe documente.
UNIX posedă un sistem de fişiere ierarhic, cu o structură
arborescentă multi-nivel ce pleacă de la directorul rădăcină (root),
simbolizată prin caracterul „/” (slash), putând de fapt să fie suportate mai
multe sisteme de fişiere simultan pe acelaşi disc. Fiecare disc este divizat în
porţiuni (partiţii) ce pot găzdui un sistem de fişiere, un domeniu de swap sau
un domeniu de date speciale.
Directorul Reprezintă nivelul cel mai de sus din sistemul de
"root" fişiere şi este simbolizat de caracterul "/" (slash).
Nu poate exista decât un singur director root
într-un sistem de fişiere UNIX.
În UNIX fişierele sunt interpretate sub forma unor şiruri de octeţi;
astfel, cu toate că o aplicaţie face o cerere pentru un fişier cu o structură
specială, nucleul stochează acel fişier pe disc ca o simplă secvenţă de octeţi,
organizând fişierele în directoare. Funcţia de bază a sistemului de fişiere
este aceea de a oferi servicii de fişiere aplicaţiilor respective fără ca acestea
să fie preocupate de structura specială de stocare hardware.
Un fişier reprezintă un şir de octeţi ce aparţine unui director.
Conceptual, un fişier UNIX este precum un document îndosariat (dosarul
este directorul din care face parte). Fişierul poate stoca informaţii diverse:
text, grafică, video, sunet, imagine etc. Orice fişier din sistem are un nume;

26
UNIX

lungimea numelor de fişiere UNIX este în general limitată la 255 de


caractere. Caracterele valide sunt: orice caracter alfabetic, numeric, liniuţa
de subliniere underscore ( _ ) şi punctul (.). Nu se folosesc spaţii în numele
fişierelor, precum şi următoarele caractere speciale:
! " ` ' ; / \ $ * & < > ( ) | { } [ ] ~.
Directorul este un caz particular de fişier ce arată ca un cuprins de
carte. El conţine două coloane de informaţie - numerele inode ale fişierelor
şi numele fişierelor. Fiecare director conţine o referinţă către el însuşi
(identificat prin semnul „.”) şi către directorul părinte (identificat prin „..”).
Chiar şi directorul rădăcină – root – conţine o referinţă către directorul
părinte, care în acest caz este o referinţă către el însuşi. Directoarele pot
conţine subdirectoare şi fişiere. La rândul lor, subdirectoarele pot conţine
alte subdirectoare şi alte fişiere. Orice sistem de operare posedă o anumită
modalitate de structură a directoarelor pentru organizarea informaţiei pe
hard-disc; în UNIX un director se numeşte directory, iar în Windows şi
MacOS un director se numeşte folder, având însă aceeaşi semnificaţie.
Chiar dacă detaliile sistemului de fişiere pot diferi în funcţie de tipul
sistemului, următoarele componente sunt comune pentru majoritatea
sistemelor de fişiere:
Blocul de boot • Aici se află procedurile de boot
Super-blocul • Conţine mărimea şi starea sistemului de fişiere
• Informaţiile inode (numărul total alocat, total liber,
numerele inodurilor libere)
• O copie a acestuia se află în memorie şi una
pe hard-disc
Tabela de inoduri • Tipul şi permisiuni
• Numărul de hard link-uri
• UID pentru proprietar
• GID pentru proprietar
• Dimensiunea în bytes
• Indicatorii dată şi timp (creare, ultima accesare
şi ultima modificare)
• Adresele de bloc de pe disc
Blocurile de stocare • Blocuri de date
• Fişiere obişnuite - conţinut
• Fişiere director – nume de fişiere şi numerele
inodurilor

O caracteristică aparte a sistemului de fişiere UNIX o constituie


legăturile. O legătură (link) reprezintă o posibilitate a unui fişier sau de

27
Sistemul de fişiere UNIX şi comenzi

acces la acesta prin mai multe nume. O legătură este, de fapt, o intrare
într-un director ce face redirectarea spre un fişier stocat în alt director sau
chiar spre un întreg alt director.
Directorul root are o serie de subdirectoare (ce diferă în funcţie de
implementarea UNIX), printre care cele mai importante sunt, de regulă:
"bin", "dev", "etc", "opt", "lib","mnt", "tmp","home" şi "usr".
Aceste directoare au următorul conţinut:

/bin Comenzi UNIX


/dev Director pentru dispozitive speciale
/etc Programe şi fişiere de date suplimentare
/lib Directorul bibliotecii de programe C
/mnt Directorul mount; rezervat pentru montarea sistemelor de
fişiere
/opt Conţine aşa numitele „software storage objects” (SSO's)
/tmp Director temporar
/usr Conţine rutine utilizator
/var Fişiere obiect nepartajate
/home Directorul utilizatorilor sistemului

Unele dintre directoarele UNIX sunt mai „interesante” decât altele;


existenţa şi conţinutul acestor directoare depinde de varianta de UNIX
utilizată. Nu există practic reguli foarte stricte cu privire la localizarea
fişierelor. Spre exemplu, pentru a găsi anumite fişiere sistem binare, putem
căuta într-unul din directoarele: /bin, /usr/bin, /sbin, /usr/sbin şi chiar în /etc.
Fişierele binare moştenite se pot găsi în /usr/ucb sau /usr/bsd. Alte
fişiere executabile se pot găsi în alte locuri din structura de directoare. Şi
legăturile simbolice trebuie considerate cu atenţie; directorul /home poate fi
definit ca având propriul sistem de fişiere (montat separat) sau poate fi
definit ca subdirector al rădăcinii. Pe serverele Solaris, spre exemplu, el este
găsit ca subdirector al directorului /export; de regulă, acest director conţine
directoarele home ale utilizatorilor existenţi în sistem.
Spaţiul dedicat stocărilor temporare este localizat, de regulă, în
directorul /tmp. Acest director poate fi accesat pe majoritatea sistemelor ca
/tmp, /usr/tmp sau /var/tmp. Două dintre cele trei referinţe vor fi directoare
reale iar cea de-a treia va fi o legătură simbolică (symlink) către una din
primele două. Varianta de UNIX utilizată va influenţa care dintre aceste
referinţe este legătura simbolică. Se recomandă totuşi ca aceste directoare să

28
UNIX

fie reconfigurate astfel încât o singură referinţă să fie un director real, iar
celelalte două să fie legături simbolice către acest director. Mai mult, acest
director se recomandă a fi montat separat. Deoarece utilizatorii pot scrie
fişiere de dimensiuni mari în spaţiul temporar /tmp, montarea separată
asigură protecţia directoarelor „/” şi „/usr” faţă de umplerea cu fişiere
temporare. O regulă general valabilă în acest sens este aceea că utilizatorii
nu trebuie să aibă drept de creare şi ştergere de fişiere în locaţiile „/”
şi „/usr”.
Directorul /tmp trebuie să aibă permisiuni de acces 1777, nu 777.
Dreptul de acces 777 permite ca orice utilizator să aibă drepturi depline în
directorul /tmp, în timp ce 1777 setează aşa-numitul „sticky bit” ce
înseamnă că directorul poate fi modificat sau şters doar de către proprietar.
Directorul /usr poate fi montat separat sau poate fi subdirector al lui
„/”. Subdirectoarele sale pot fi:
ƒ bin – fişiere binare
ƒ include – fişiere pentru programare
ƒ lib – biblioteci de programe
ƒ local – pachete software locale, biblioteci, fişiere include, fişiere
binare (de regulă /usr/local se montează separat pentru a nu
umple directorul /usr).
ƒ sbin – fişiere de sistem binare
ƒ share – informaţie partajată, inclusiv pagini de manual.
Directorul /var poate fi montat separat (ceea ce este recomandat) sau
poate fi subdirector al lui „/” sau „/usr”. Subdirectoarele sale pot fi:
ƒ adm – stocare fişiere log (Solaris)
ƒ crash – diagnostic în situaţii de oprire bruscă
ƒ log – stocare fişiere log (Solaris şi Linux Red Hat)
ƒ mail – zona de stocare pentru poşta electronică
ƒ spool – zona de spool pentru printare, utilitarul cron şi alte servicii
ƒ yp – zona de stocare pentru fişierul de configurare NIS.

2.2 Partiţii
Partiţiile reprezintă modalitatea de organizare a spaţiului de pe disc
la nivel jos. Partiţiile sunt independente de sistemul de operare; un sistem de
operare solid recunoaşte diviziunile la nivel jos de pe disc şi adresează
fiecare partiţie ca pe un echipament logic separat.

29
Sistemul de fişiere UNIX şi comenzi

Toate informaţiile cu privire la partiţii sunt localizate în aşa-numita


tabelă de partiţii (partition table), stocată în eticheta de disc sau în header-ul
de volum (volume header) al discului fizic. Aceasta este modalitatea prin
care discurile păstrează propriile informaţii referitoare la modalitatea de
aranjare a datelor şi de aceea ele pot fi transferate de la un calculator la altul
fără riscul pierderii informaţiei. De asemenea, partiţiile permit existenţa mai
multor sisteme de operare pe acelaşi calculator, instalate în partiţii diferite.
Iniţial, exista o corespondenţă strictă între partiţii şi sistemele de fişiere,
partiţiile fiind considerate drept containere pentru sistemele de fişiere.
Acum un sistem de fişiere se poate întinde pe mai multe partiţii prin
utilizarea volumelor logice, astfel încât partiţiile pot fi considerate elemente
de bază pentru stocarea informaţiei în loc de a fi interpretate drept simple
containere.
Deoarece partiţiile sunt diviziuni la nivel hardware ale discurilor, ele
pot oferi o protecţie la nivel jos împotriva supra-încărcării. Utilizându-se
anumite politici de partiţionare, unele dintre partiţii pot fi supra-încărcate
fără a afecta performanţele generale ale sistemului; în orice caz, umplerea
unei partiţii nu are cum să afecteze spaţiul altei partiţii.
2.3 Spaţiul de swap
Toate varietăţile de UNIX necesită minimum două partiţii: partiţia
de root (/) şi partiţia pentru swap. În cazul (destul de puţin întâlnit în
practică) în care există doar aceste două partiţii, partiţia / va conţine întregul
sistem de operare, aplicaţiile, fişierele de configurare, conturile locale ale
utilizatorilor, etc. Spaţiul de swap sau, pe scurt, swap, permite accesul direct
al sistemului de operare la spaţiul brut de pe disc, fără implicarea sistemului
de fişiere. Swap-ul a fost construit pentru a acţiona ca o extensie a memoriei
principale (RAM – Random Access Memory) a calculatorului, permiţând,
prin implementarea mecanismului memoriei virtuale, accesul la o cantitate
de memorie ce nu este limitată de capacitatea memoriei RAM ci de spaţiul
liber de pe disc.
Principalele mecanisme utilizate de către sistemul de operare pentru
a accesa spaţiul de swap sunt paginarea (paging) şi interschimbarea
(swapping). Spaţiul liniar al memoriei unui calculator este limitat iar o parte
din acesta este rezervat pentru stocarea unor programe ce rămân rezidente în
memorie (sistemul de operare, tabelele de paginare, etc.) pentru a fi accesate
rapid când este nevoie de ele. De asemenea, multe procese şi obiecte
program nu necesită prezenţa permanentă în memorie ca în cazul
programelor rezidente. Atunci când sistemul de operare găseşte un astfel de
proces, se caută modalităţi de înlocuire a lui cu altul ce trebuie executat şi
deci încărcat în memorie.
30
UNIX

Procedeul de interschimbare sau swapping este unul dintre


mecanismele utilizate de către sistemul de operare pentru a administra
alocarea memoriei. Atunci când un proces este interschimbat, el este copiat
din memorie în spaţiul de swap împreună cu toate datele asociate şi alte
informaţii de stare. În acest fel, porţiunea din memorie alocată procesului
devine liberă şi poate fi utilizată pentru a stoca alt proces (program). În
momentul în care este nevoie din nou de procesul aflat în swap, acesta este
transferat rapid din swap în memoria principală pentru a fi executat. În
esenţă, procedeul de swapping constă în transferul unui proces din memorie
în spaţiul de swap şi viceversa. Atunci când procedeul de swapping este
intens utilizat înseamnă că sistemul are nevoie de resurse hardware
suplimentare (de regulă mai multă memorie RAM).
Paginarea utilizează, de asemenea, spaţiul de swap. Spre deosebire
de procedeul de interschimbare, care stochează împreună cu procesul şi o
serie întreagă de informaţii legate de starea procesului, paginarea stochează
doar porţiuni ale codului executabil al unui proces. Paginarea reprezintă o
metodă obişnuită de administrare a memoriei de către sistemul de operare,
metodă în care acesta determină în prealabil dimensiunea segmentelor de
memorie (denumite pagini) ce pot fi menţinute în memoria principală.
Referitor la spaţiul de swap, unele variante de UNIX depind mult de
acest spaţiu. Solaris-ul firmei Sun foloseşte spaţiul de swap pentru directorul
/tmp în mod implicit.
2.4 Tipuri de fişiere
Principalele tipuri de fişiere existente pe un sistem UNIX sunt:
ƒ Fişiere text
ƒ Fişiere de date
ƒ Fişiere sursă (ce conţin codul sursă al unor programe)
ƒ Fişiere executabile
ƒ Programe shell
ƒ Fişiere legătură
ƒ Fişiere asociate unor dispozitive

a) Fişiere text
Cel mai simplu tip de fişiere îl constituie fişierul text, ce conţine
doar caractere ca acelea pe care le puteţi citi în cadrul acestui capitol. Aceste
caractere ASCII (American Standard Code for Information Interchange)
sunt literale sau caractere numerice ce reprezintă manifestarea muncii pe

31
Sistemul de fişiere UNIX şi comenzi

care o facem. Dacă utilizăm, spre exemplu, un editor UNIX pentru a crea un
mesaj pentru poşta electronică atunci creăm un fişier text în cele mai multe
dintre cazuri. Avem în continuare un exemplu de fişier ASCII de pe un
sistem Linux:

:.Z: : :/bin/compress -d -c
%s:T_REG|T_ASCII:O_UNCOMPRESS:UNCOMPRESS
: : :.Z:/bin/compress -c %s:T_REG:O_COMPRESS:COMPRESS
:.gz: : :/bin/gzip -cd %s:T_REG|T_ASCII:O_UNCOMPRESS:GUNZIP
: : :.gz:/bin/gzip -9 -c %s:T_REG:O_COMPRESS:GZIP
: : :.tar:/bin/tar -c -f - %s:T_REG|T_DIR:O_TAR:TAR
: : :.tar.Z:/bin/tar -c -Z -f -
%s:T_REG|T_DIR:O_COMPRESS|O_TAR:TAR+COMPRESS
: : :.tar.gz:/bin/tar -c -z -f -
%s:T_REG|T_DIR:O_COMPRESS|O_TAR:TAR+GZIP

b) Fişiere de date
Fişierele de date sunt fişierele ce conţin date utilizate de diverse
aplicaţii de pe sistem. Dacă utilizăm un program de tipul FrameMaker
pentru scrierea unei cărţi, fişierele create cu acest program vor fi de tipul
suportat de acesta (la fel ca şi fişierele speciale de date de pe un sistem
Windows). Fişierele de date conţin pe lângă informaţia în sine (de tip text)
şi informaţii speciale de formatare. Acelaşi lucru se petrece şi în cazul unui
fişier bază de date, ce conţine atât date ce pot fi citite cât şi informaţii
specifice formatării respective.
c) Fişiere cod sursă
Fişierele cod sursă sunt fişiere ce conţin date scrise într-un limbaj de
programare precum C, C++, Java, Pascal, Fortran etc. Aceste fişiere au, de
regulă, extensii conforme cu limbajul în care au fost scrise; spre exemplu,
un program sursă scris în C va avea extensia „.c”.
d) Fişiere executabile
Fişierele executabile reprezintă programe obţinute cu ajutorul unui
compilator (sau interpretor) şi editor de legături ce pot fi rulate (executate).
Dacă încercăm să citim un fişier executabil ca pe un fişier text, vom obţine o
serie de caractere ciudate şi chiar sunete; în urma unei astfel de „citiri” se
pot pierde setările ecranului. Majoritatea comenzilor UNIX sunt programe
executabile (vezi directorul /bin).

32
UNIX

e) Programe de tip shell


Un fişier de tip shell este atât un fişier text cât şi un fişier ce poate fi
rulat. El conţine linii text ce reprezintă instrucţiuni legate de programarea
shell; de regulă, prima linie din program este o linie ce începe cu secvenţa
de caractere “#!” şi precizează tipul de shell utilizat. De exemplu, linia:
#!/bin/sh

specifică faptul că se utilizează shell-ul Bourne care este shell-ul


clasic pentru un sistem UNIX. În general, caracterul “#” reprezintă
modalitatea de inserare a comentariilor în program; astfel, tot ce urmează
după “#” şi până la sfârşitul liniei este considerat comentariu.
f) Fişiere de tip legătură
Un fişier legătură (link) este o referinţă către un fişier stocat în altă
locaţie în sistem. În loc să avem două sau mai multe copii ale unui fişier pe
disc, putem crea o legătură către un fişier deja existent pe sistem. Un mod
deosebit de utilizare a legăturilor pe un sistem UNIX a fost acela legat de
apariţia unei noi versiuni a sistemului de operare. Cum locaţiile fişierelor se
modifică uneori la apariţia unei noi versiuni a sistemului de operare, se
folosesc legături de la locaţiile vechi către cele noi în loc de a învăţa noile
locaţii. În momentul utilizării unei comenzi folosind vechea locaţie, legătura
face referire la comanda ce acum se află în alt loc pe disc.
g) Fişiere asociate unor dispozitive
Fişierele asociate unor dispozitive, denumite în UNIX “device
special files”(sau, pe scurt, fişiere device) conţin informaţii legate de
componente hardware ale calculatorului şi sunt fişiere speciale cu referire
(de regulă) la funcţii de administrare a sistemului. Sistemul de operare
UNIX tratează dispozitivele hardware ca fişiere, avantajul acestei metode de
administrare fiind acela că permite accesul la disc precum o simplă operaţie
de acces (Input/Output) la un fişier. Dispozitivele instalate pe computer pot
fi accesate prin intermediul unor astfel de fişiere speciale. Discul, spre
exemplu, poate fi accesat fie printr-un fişier de tip bloc, fie printr-unul de tip
caracter.

33
Sistemul de fişiere UNIX şi comenzi

Semnificaţia subdirectoarelor din /dev la Solaris


Tabelul 2.1

Directorul Descriere
/dev/cua Director pentru dispozitive seriale
/dev/dsk Director pentru dispozitive de tip bloc
(hard-discuri, CD-ROM-uri, etc.)
/dev/fd Director pentru unităţi floppy

/dev/kmem Director pentru memoria virtuală kernel


/dev/log Director socket către login-ul sistem
/dev/mem Dispozitiv pentru memoria fizică
/dev/null Dispozitivul „null”
/dev/pts Pseudo-terminale
/dev/rdsk Director pentru echipamente device de tip
caracter
/dev/rmt Director pentru medii de stocare movibile
– bandă magnetică
/dev/swap Spaţiul de swap
/dev/tty Director pentru linii terminal
/dev/zero Sursă „null byte”

Fişierele device de tip caracter sunt cel mai des folosite pentru
proceduri de copiere de octeţi (ca în cazul comenzii dd). Majoritatea
echipamentelor de bandă au asociate doar fişiere device de tip caracter.
Fişierele device de tip bloc sunt utilizate pentru transferul de date în blocuri
de octeţi, ceea ce este mai avantajos şi mai rapid pentru majoritatea
aplicaţiilor. Pentru varianta de UNIX Solaris, hard-discurile au asociate atât
un fişier device de tip caracter cât şi unul de tip bloc. Fiecare dintre acestea
sunt folosite în cazuri diferite. Operaţiile uzuale se fac prin intermediul
fişierelor bloc, însă crearea sistemului de fişiere se face cu ajutorul fişierelor
caracter.
Toate fişierele device standard UNIX sunt păstrate în directorul /dev
(unele implementări de Linux Red Hat păstrează acest sistem). În varianta
UNIX Solaris şi în unele noi implementări de Red Hat însă, conţinutul lui
/dev tinde să fie o combinaţie de fişiere device şi de legături simbolice către
fişiere device situate în alte directoare. Într-un astfel de sistem, directorul

34
UNIX

/dev acţionează ca un redirector organizaţional. În Red Hat directorul se


numeşte /devfs iar sub Solaris se intitulează /devices. Fişierele şi directoarele
din directorul /dev variază foarte mult, chiar între versiuni ale aceleiaşi
variante de sistem de operare. În tabelul 2.1 sunt prezentate o serie dintre
subdirectoarele reprezentative pentru /dev întâlnite la Solaris.
În continuare vom prezenta câteva comenzi de bază referitoare la
manipularea fişierelor şi directoarelor pe un sistem UNIX.
2.5 Comenzi referitoare la fişiere şi directoare
Pentru a putea naviga în cadrul sistemului de fişiere trebuie să
cunoaştem în principiu două comenzi: prima comandă (pwd) afişează
localizarea curentă (directorul în care ne aflăm la un moment dat) iar cea de-
a doua comandă (cd) este utilizată pentru a schimba directorul curent. Să
vedem mai întâi care este sintaxa generală a unei comenzi UNIX.
În momentul în care suntem conectaţi la sistem sau atunci când
folosim o fereastră terminal, pe acran apare un prompter. În cazul
shell-urilor Bourne şi Korn, prompterul este semnul dolar ($) pentru un
utilizator obişnuit şi semnul diez (#) pentru utilizatorul root. În cazul
shell-ului C, semnul special pentru prompter pentru un utilizator obişnuit
este semnul procent (%). Odată cu apariţia prompterului, putem introduce
comenzi la linia de comandă. Formatul general al unei comenzi UNIX este:

$ comanda [optiune(optiuni)] [argument(e)]

În formatul general de mai sus, identificăm următoarele componente:


semnul dolar $ reprezintă prompterul shell, comanda reprezintă programul
executabil, optiune/optiuni identifică posibilitatea modificării programului
executabil pentru a rula în condiţii specifice iar argument/argumente
reprezintă fişier (fişiere) sau director (directoare), inclusiv cu calea către
fişierul sau directorul specificat, sau un text. Separarea acestor componente
se face prin semnul spaţiu; pe o singură linie putem introduce până la 256 de
caractere (nu se recomandă, desigur, folosirea unui număr atât de mare de
caractere pe o singură linie). Toate comenzile UNIX sunt scrise cu litere
mici. Opţiunile sunt formate din litere precedate de semnul liniuţă sau minus
(-). Se pot combina mai multe opţiuni folosind un singur semn minus.
Opţiunile pot fi atât litere mici cât şi litere mari, în funcţie de comandă. Nu
toate comenzile necesită toate cele 3 componente. Se pot scrie mai multe
comenzi pe aceeaşi linie, separate de caracterul punct şi virgulă (;).
Principala comandă de navigare în cadrul sistemului de fişiere UNIX
este cd (change directory). O altă comandă folosită pentru a afla directorul
curent este pwd (print working directory).

35
Sistemul de fişiere UNIX şi comenzi

Comanda pwd este des utilizată pentru a ne reaminti directorul în


care ne alfăm la un moment dat (directorul curent). Comanda pwd este
folosită fără opţiuni si fără argumente; trebuie doar să tastăm pwd la linia de
comandă şi să apăsăm tasta ENTER. Presupunând că ne aflăm în directorul
/home/serban/test, vom obţine următorul răspuns al comenzii pwd:
$ pwd
/home/serban/test

Modificarea directorului curent şi navigarea în cadrul structurii


sistemului de fişiere şi directoare se face utilizând comanda cd (change
directory). Această comandă acceptă ca argument atât căi relative cât şi căi
absolute. Sintaxa generală a acestei comenzi este:

$ cd [nume_director]

Exemple:

$ cd /tmp

Schimbă directorul curent în directorul /tmp, acest director devenind


directorul curent, iar:

$ cd /usr/stud

Schimbă directorul curent în directorul /usr/stud.

Observaţie:
Există două modalităţi de referire a unei căi în structura de fişiere
UNIX: calea absolută şi calea relativă. O cale absolută este aceea care
pleacă din rădăcină, deci începe cu "/". Un exemplu de cale absolută este:
/usr/bin. O cale relativă nu începe cu "/", ci reprezintă o localizare relativă la
directorul curent de lucru. Căile ce încep cu „../”, „./” sau altceva diferit de
„/” sunt căi relative. Căile relative au avantajul că sunt mai scurte decât căile
absolute; pentru a le utiliza însă, trebuie să cunoaştem directorul în care ne
aflăm deoarece acesta este punctul de plecare al căii relative.
Un exemplu de cale relativă întâlnim în exemplul următor:
$ cd ../../bin

36
UNIX

Uneori este mai uşor să utilizăm meta-caractere. În UNIX, caracterul


star (*) este un caracter special (meta-caracter) şi semnifică orice combinaţie
de caractere. Spre exemplu, comanda "cd /u*/s*" ne poziţionează în
directorul /usr/stud dacă acest director este singurul ce corespunde
şablonului specificat. Mai multe noţiuni despre meta-caractere vor fi
prezentate în cadrul capitolului curent.
Alte exemple:
$ cd

Comanda cd apelată fără nici un argument ne poziţionează în


directorul home.

$ cd ..

Această comandă ne poziţionează în directorul părinte al directorului


curent (cu un nivel mai sus în structura arborescentă de directoare).
$ cd ~

Această comandă ne poziţionează în directorul home.

$ cd ~-

Dacă se foloseşte shell-ul Korn, această comandă ne poziţionează în


directorul anterior de lucru.

$ cd ~nume_utilizator

Această comandă ne poziţionează în directorul home al utilizatorului


identificat prin nume_utilizator.

Listarea conţinutului unui director

Comanda ls (list) este folosită pentru listarea fişierelor şi


directoarelor, cu informaţii despre acestea. Comanda ls apelată simplu, fără
opţiuni, listează fişierele din directorul curent. Fişierele ale căror nume
încep cu "." sunt considerate fişiere ascunse şi nu vor fi afişate în acest caz.
Fişierele ascunse sunt, de regulă, folosite pentru a personaliza mediul de
lucru al unui utilizator. Aceste fişiere nu sunt implicit afişate deoarece nu
sunt editate frecvent. Directorul curent (.) şi directorul părinte (..) sunt şi ele
ascunse şi nu sunt afişate deoarece încep cu semnul punct (.).

37
Sistemul de fişiere UNIX şi comenzi

Comanda ls are o serie întreagă de opţiuni, fiind una dintre cele mai
folositoare şi flexibile comenzi UNIX.

Exemple:

$ ls -a

Această comandă este folosită pentru a afişa toate fişierele, inclusiv


cele ascunse.

$ ls -l

Această comandă ne oferă un "listing lung", adică informaţii


suplimentare legate de fişiere (nu numai numele acestora). Aceste informaţii
cuprind date referitoare la drepturile de acces la fişiere, proprietarul şi
grupul cărora aparţin, dimensiune, data şi ora ultimei modificări.
drwxr-xr-x 2 root sys 60676 Aug 22 1994 Lib
-r--r--r-- 1 root sys 60676 Aug 22 1994 README
drwxr-xr-x 2 root sys 60676 Aug 22 1994 Source
-rwxr-xr-x 2 root sys 60676 Aug 22 1994 gzexe
-rwxr-xr-x 2 root sys 60676 Aug 22 1994 gzip
-rwxr-xr-x 1 bin bin 242436 Feb 20 16:07 httpd
-rwsr-xr-x 1 uucp uucp 599604 Sep 22 1995 kermit
-rwxr-x--x 1 root sys 171195 Jan 22 12:15 memhog
-rwxr-x--x 1 root sys 5599 Jan 22 12:15 nlsym
-rwxr-xr-x 2 root sys 553836 Feb 20 16:40 perl
-rwxr-xr-x 2 root sys 553836 Feb 20 16:40 perl5.003
-rwxr-xr-x 1 root sys 13855 Feb 20 16:40 perlbug
-rwxr-xr-x 1 root sys 8984 Feb 20 16:40 perldoc
drwxr-xr-x 2 root sys 60676 Aug 22 1994 src
-rwxr-x--x 1 root sys 108781 Jan 22 12:15 u486mon

Figura 2.2 Exemplu de listare generat de comanda ls -l

38
UNIX

Funcţionalităţile celor două opţiuni de mai sus pot fi combinate


folosind comanda ls -al. În figura 2.2 avem un exemplu de listare a fişierelor
dintr-un director.
Alte exemple:

$ ls -al /tmp

Se poate specifica în mod explicit directorul pentru care să se facă


listarea. Astfel, comanda anterioară va lista fişierele conţinute în directorul
tmp.

$ ls -alR /usr | more

Comanda anterioară va lista informaţiile despre fişierele din


directorul /usr, precum şi din toate subdirectoarele acestuia. Opţiunea care
determină acest lucru este -R. Un exemplu de listing pentru comanda ls -alR
este prezentat în figura 2.3. Comanda more precizează că afişarea se va face
pagină cu pagină.

Figura 2.3 Exemplu de listing al comenzii ls -alR

$ ls -ld /usr

39
Sistemul de fişiere UNIX şi comenzi

Comanda anterioară listează informaţii despre însăşi directorul /usr


şi nu despre conţinutul acestuia. Aceste informaţiii sunt utile atunci când
vrem să verificăm drepturile de acces la un director.
În fiecare linie din listingul comenzii ls –al (ca cel din figura 2.2),
primul caracter reprezintă tipul fişierului (d pentru director, - pentru fişier
simplu, l pentru fişier legătură, etc.). Următoarele 9 caractere reprezintă
drepturile de acces la fişier pentru utilizatorul care este proprietarul
fişierului, pentru grupul din care face parte proprietarul şi pentru ceilalţi
utilizatori (în această ordine).

$ ls -F

Figura 2.4 Listing al comenzii ls -F

Această comandă afişează informaţii legate de tipul fişierelor. Dacă


fişierul afişat este director, numele acestuia este urmat de semnul slash (/).
Dacă fişierul este un fişier simplu ASCII, fără format special, nu apare nici
un simbol special după numele acestuia. În cazul unei aplicaţii, comenzi sau
fişier script ce poate fi executat, numele fişierului este urmat de caracterul
asterisk (*).
Dacă numele fişierului este urmat de simbolul at (@) înseamnă că
acest fişier este o legătură simbolică. În figura 2.4 avem un exemplu de
listing pentru comanda ls -F.

40
UNIX

Drepturile de acces la fişiere şi directoare

d r w x r w x r w x

d r w x r w - r - -

- r w x r - - r - -

- r w x - - - - - -

- r - x - - - - - -

Cele 10 coloane care reprezintă drepturile de acces la fişiere sunt:


Să analizăm în continuare semnificaţia acestor coloane:
Coloana 1 Coloana 2-4 Coloana 5-7 Coloana 8-10
d r w x r w x r w x
d r w x r w - r - -
- r w x r - - r - -
- r - x - - - - - -

Coloana 1: Ne arată faptul că un fişier este director(d), fişier obişnuit


(-), sau un tip special de fişier.
Coloanele 2-4: Ne arată care sunt drepturile de acces la fişier pentru
utilizatorul care este proprietarul fişierului. Drepturile de acces pot fi: de
citire (r), scriere (w), şi execuţie (x).
Coloanele 5-7: Ne arată care sunt drepturile de acces la fişier pentru
grupul proprietar al fişierului. Drepturile de acces pot fi aceleaşi: citire (r),
scriere (w) şi execuţie (x).
Coloanele 8-10: Ne arată care sunt drepturile de acces la fişier pentru
utilizatorii care nu sunt în grupul proprietar al fişierului (others). Drepturile
de acces pot fi aceleaşi: citire (r), scriere (w) şi execuţie (x).
Drepturile de acces la fişiere şi directoare se pot modifica folosind
comanda chmod (change mode). Mai multe despre această comandă în
capitolul 5.

41
Sistemul de fişiere UNIX şi comenzi

Tipuri de fişiere UNIX


Tabelul 2.5
Tipul de fişier b) Descriere
- Fişier simplu ("ordinary file")
d Director
b Fişier bloc ("block special")

c Fişier caracter ("character special")


l Fişier legătură ("link")
Fişier de memorie partajată ("shared
M
memory")
P Fişier pipe ("named pipe")
S Fişier semafor ("semaphore")

Tipurile de fişiere UNIX sunt prezentate în tabelul 2.5.


Caracteristici:

ƒ Fişierele simple (-)


• Nu este impusă nici o structură asupra conţinutului - acesta
reprezintă o înşiruire de octeţi;
• Aceste fişiere pot fi text (ASCII) sau binare.

ƒ Fişiere director (d)


• Reprezintă un fel de tabel de fişiere;
• Are o structură internă precis definită;
• Oferă posibilitatea organizării sistemului de fişiere.

ƒ Fişierele bloc (b)


• Identifică un dispozitiv;
• Este un bloc de I/O;
• Pot identifica unităţi floppy, hard-discuri, unităţi de bandă.

ƒ Fişiere caracter (c )
• Identifică un dispozitiv;
• Reprezintă caractere de I/O;
• Pot identifica porturi seriale, paralele (terminale, imprimante).

42
UNIX

ƒ Fişiere de legătură simbolică (l)


• Sunt fişiere pointer către alt fişier existent;
• Sunt de regulă folosite pentru a oferi un alias altui fişier.

ƒ Fişiere de memorie partajată (m)


• Permit mai multor programe să acceseze un spaţiu comun de
memorie;
• Folosite de regulă de programele de aplicaţii.

ƒ Fişiere pipe (p)


• Folosite pentru a transmite date între comenzi sau programe.

ƒ Fişiere semafor (s)


• Folosite pentru sincronizarea proceselor active concurente;
• Folosite de programele de aplicaţii.

Nr de legături
Proprietarul Dimensiunea în octeţi
Grupul Data Numele fişierului

drwxr-xr-x 2 root sys 60676 Aug 22 1994 Lib


-r--r--r-- 1 root sys 60676 Aug 22 1994 README
drwxr-xr-x 2 root sys 60676 Aug 22 1994 Source
-rwxr-xr-x 2 root sys 60676 Aug 22 1994 gzexe
-rwxr-xr-x 2 root sys 60676 Aug 22 1994 gzip
-rwxr-xr-x 1 bin bin 242436 Feb 20 16:07 httpd
-rwsr-xr-x 1 uucp uucp 599604 Sep 22 1995 kermit
-rwxr-x--x 1 root sys 171195 Jan 22 12:15 memhog
-rwxr-x--x 1 root sys 5599 Jan 22 12:15 nlsym
-rwxr-xr-x 2 root sys 553836 Feb 20 16:40 perl
-rwxr-xr-x 2 root sys 553836 Feb 20 16:40 perl5.003
-rwxr-xr-x 1 root sys 13855 Feb 20 16:40 perlbug
-rwxr-xr-x 1 root sys 8984 Feb 20 16:40 perldoc
drwxr-xr-x 2 root sys 60676 Aug 22 1994 src
-rwxr-x--x 1 root sys 108781 Jan 22 12:15 u386mon

43
Sistemul de fişiere UNIX şi comenzi

Considerând listingul anterior, putem observa şi alte informaţii


legate de fişierele şi directoarele afişate:
ƒ Numărul de legături (link-uri) – reprezintă numărul de legături
simbolice către acest fişier;
ƒ Proprietarul – reprezintă numele utilizatorului care deţine acest
fişier;
ƒ Grupul – reprezintă numele grupului de utilizatori din care face
parte proprietarul;
ƒ Dimensiunea - este exprimată în octeţi;
ƒ Data – data şi ora ultimilor modificări făcute asupra fişierului
sau data de creare a fişierului;
ƒ Numele fişierului.

Observaţie
Pe un sistem Linux, comanda ls derivă din proiectul GNU fileutils,
având o întreagă serie de opţiuni şi caracteristici speciale. Spre exemplu,
numele de fişiere pot apărea listate în culori în funcţie de tipul de fişier.
Culorile folosite la afişare sunt definite în fişierul /etc/DIR_COLORS;
acestea se pot personaliza folosind şi fişierul .dir_colors din directorul
curent home.
Formatul acestui fişier este definit în fişierul /etc/DIR_COLORS.
Pentru a afişa numele fişierelor fără culori dar cu simboluri, se pot folosi
opţiunile --color şi --classify. În mod asemănător cu opţiunea -F,
simbolurile --classify sunt următoarele: „/” pentru directoare, „*” pentru
programe, „@” pentru legături simbolice, „|” pentru fişiere de tip pipe şi „=”
pentru fişiere de tip socket.
Astfel, listingul comenzii:

$ ls --color=never --classify
studenti/ lista.sh* text.sub

semnifică faptul că studenti este director, iar fişierul lista.sh este executabil.

44
UNIX

2.6 Caractere speciale în UNIX


Caracterele speciale sau metacaracterele sunt caractere cu
semnificaţie specială pentru shell-ul UNIX. În general, caracterele de pe
tastatură care nu sunt alfanumerice sunt metacaractere. Metacaracterele sunt
utilizate împreună cu majoritatea comenzilor UNIX pentru a oferi o mai
mare flexibilitate.
Câteva dintre metacaracterele folosite în UNIX sunt similare cu cele
utilzate în MS-DOS. Caracterul asterisk (*) şi semnul de întrebare (?) sunt
metacaractere cunoscute şi sub numele de wildcard-uri, fiind folosite pentru
a lucra cu grupuri de fişiere într-un mod mai eficient. În tabelul 2.6 sunt
prezentate câteva dintre cele mai folosite metacaractere împreună cu o
scurtă descriere a funcţionalităţii acestora.
Fiind vorba despre nişte caractere speciale, trebuie să nu folosim
metacaractere atunci când denumim un fişier sau un director. Caracterul
punct ( . ) şi caracterul underscore ( _ ) sunt unicele caractere non
alfanumerice care nu sunt metacaractere. Din această cauză aceste două
caractere pot fi folosite în cadrul numelor de fişiere. Semnul minus ( - ), cu
toate că este metacaracter, poate fi, de asemenea, utilizat în cadrul numelor
de fişiere.

Cele mai uzuale metacaractere

Tabelul 2.6
Metacaracterul Descriere Formatul comenzii

* Reprezintă orice caracter sau secvenţă *


de caractere
? Identifică un singur caracter ?
; Permite scrierea mai multor comenzi comanda;comanda
pe aceeaşi linie
[] Identifică o mulţime sau un domeniu [domeniu]
de caractere pentru o singură poziţie
> Redirectează ieşirea unei comenzi comanda > fisier
către un fişier în loc de ecran (stdout -
fişierul standard de ieşire).
< Redirectează intrarea unei comenzi comanda < fisier
dintr-un fişier în loc de tastatură (stdin
- fişierul standard de intrare)
2> Redirectează eroarea unei comenzi comanda 2> fisier
către un fişier în locul ecranului
>> Adaugă ieşirea unei comenzi la un comanda >> fisier
fişier existent (concatenare)

45
Sistemul de fişiere UNIX şi comenzi

Metacaracterul Descriere Formatul comenzii

| (semnul pipe) Preia ieşierea unei comenzi şi o comanda | comanda


pasează ca intrare comenzii următoare
$ Indicatorul prompter-ului standard Nu se aplică
pentru shell-ul Bourne şi Korn
% Indicatorul prompter-ului standard Nu se aplică
pentru shell-ul C
~ Indică directorul home ~
! Re-execuţia comenzii !n, unde n este numărul
comenzii introduse

Cele mai utilizate metacaractere sunt asteriskul (*), semnul întrebării


( ? ) şi parantezele pătrate ( [ ] ).
Caracterul asterisk sau star (*) este un caracter de substituţie pentru
un caracter sau mai multe (sau nici unul !), cu excepţia caracterului punct de
început al unui fişier ascuns. Caracterul star poate fi deosebit de util în unele
situaţii, precum în cazul comenzilor ls (list), cp (copy), mv (move) sau rm
(remove). Dacă dorim să afişăm dintr-un director doar fişierele al căror
nume începe cu litera “s” putem folosi comanda ls s*. Un exemplu de listing
este în figura 2.7.

Figura 2.7 Listingul comenzii ls s*

46
1. Administrarea fişierelor şi directoarelor

3 ADMINISTRAREA FIŞIERELOR
ŞI DIRECTOARELOR

3.1 Introducere

În acest capitol vom prezenta atât comenzile de bază cât şi comenzi


mai avansate utilizate în administrarea fişierelor şi directoarelor pe un
sistem UNIX. Ne vom concentra asupra utilizării comenzilor la linia de
comandă. Cu toate că administrarea fişierelor şi directoarelor se poate face
şi prin utilizarea unei interfeţe grafice precum GNOME, spre exemplu,
există două motive suficient de puternice pentru a ne convinge că un bun
utilizator UNIX trebuie să ştie să folosească linia de comandă:
ƒ în primul rând, linia de comandă oferă posibilitatea utilizării a
numeroase opţiuni, deci oferă o mai mare flexibilitate;
ƒ în al doilea rând, prin intermediul liniei de comandă se poate
face administrarea pe un sistem aflat la distanţă, pe care nu
putem folosi o interfaţă grafică (cazul cel mai des întâlnit).

3.2 Funcţionalităţi ale liniei de comandă şi comenzi de bază

Cunoaşterea utilizării comenzilor la linia de comandă reprezintă


piatra de bază ce stă la temelia cunoaşterii sistemului de operare UNIX.
Multe dintre instrumentele de management ale sistemului de operare şi
dintre aplicaţiile de configurare a dispozitivelor hardware presupun folosirea
liniei de comandă. De asemenea, de multe ori este necesară crearea aşa
numitelor shell-scripturi, programe utilizate de regulă pentru automatizarea
unor activităţi specifice sistemului de operare.
Fişierele shell-script sunt compuse din comenzi UNIX şi sunt
asemănătoare cu fişierele de comenzi (batch) utilizate şi în alte sisteme de
operare pentru reţea.

47
UNIX

3.2.1 Folosirea combinaţiilor de control


Combinaţiile de control sunt utilizate pentru a realiza anumite sarcini
specifice, cum ar fi terminarea sau pornirea afişării pe ecran, ieşirea din
sesiunea de lucru curentă, terminarea imprimării etc. Majoritatea tastaturilor
de PC actuale au două taste de control, inscripţionate cu Ctrl şi care se
găsesc în colţurile stânga-jos şi dreapta-jos. Atunci când apare pe ecran,
semnul corespunzător tastei Ctrl este semnul caret (^). Pentru introducerea
unei secvenţe de control, se ţine apăsată tasta Ctrl şi simultan se apasă şi o
altă tastă de pe tastatură.
Cea mai uzitată secvenţă de control este probabil secvenţa Ctrl+c,
utilizată pentru întreruperea unui program sau proces ce se află în execuţie.
Această combinaţie apare pentru shell drept ^C şi se obţine în urma apăsării
simultane a tastelor Ctrl şi a tastei C.
Alte combinaţii de control care mai pot fi folosite sunt următoarele:
ƒ Ctrl+s - determină oprirea defilării informaţiei pe ecran. Această
combinaţie poate fi utilizată, spre exemplu, atunci când
vizualizăm cu ajutorul comenzii cat un fişier mai mare pe ecran
şi dorim oprirea defilării informaţiei pe ecran.
ƒ Ctrl+q - reia defilarea informaţiei pe ecran atunci când aceasta a
fost întreruptă cu Ctrl+s.
ƒ Ctrl+c - întrerupe activitatea curentă şi este des folosită pentru
oprirea forţată a programelor sau proceselor aflate în execuţie
sau în cazul unor listinguri interminabile pe ecran obţinute în
urma comenzilor man, cat sau ls. De exemplu, în cazul în care
am folosit comanda man şi vrem să oprim defilarea în continuare
a ecranelor cu paginile de manual (am văzut ceea ce ne interesa
şi vrem să terminăm afişarea), putem folosi Ctrl+c pentru a ne
întoarce la prompter (în acest caz, un rezultat identic se obţine
prin apăsarea tastei q - quit).
ƒ Ctrl+d - se foloseşte pentru a marca sfârşitul de fişier sau ieşirea
(exit). Această combinaţie este folosită fie pentru a ieşi din unele
utilitare UNIX (bc, write, etc.), pentru ieşirea dintr-o fereastră
terminal sau pentru ieşirea din sesiunea curentă de lucru (logout).
Ca o regulă generală, putem încerca combinaţia Ctrl+d ori de
câte ori Ctrl+c nu funcţionează.
ƒ Ctrl+u - se foloseşte pentru ştergerea întregii linii de comandă.
Se poate folosi în cazul în care dorim să ştergem rapid întreaga
linie deoarece ne-am hotărât să nu mai rulăm comanda introdusă.
ƒ Ctrl+w - se foloseşte pentru ştergerea ultimului cuvânt de la linia
de comandă.
48
Administrarea fişierelor şi directoarelor

ƒ Ctrl+h - se foloseşte pentru ştergerea ultimului caracter introdus


la linia de comandă. Se foloseşte atunci când suntem conectaţi la
un sistem la distanţă şi tasta Backspace nu funcţionează deoarece
pe sistemul de la distanţă această tastă nu este setată să acţioneze
precum combinaţia Ctrl+h.

3.2.2 Determinarea tipului unui fişier


În cazul lucrului cu diverse fişiere este deosebit de util să cunoaştem
tipul fişierului cu care lucrăm. În acest sens, putem folosi:
Comanda file
Comanda file este folosită pentru a determina tipul unui anumit
fişier. Ea diferă puţin pentru fiecare implementare UNIX. Pentru un sistem
UNIX, listingul în cazul unui fişier text va fi:

$ file temp.txt
temp.txt: ascii text

În exemplul următor avem cazul unui sistem Linux:


$ file serban
serban: ASCII text

Alt exemplu consideră afişarea tipurilor de fişiere al căror nume


începe cu litera „c” din directorul /bin:
/bin $ file c*

cat: ELF 32-bit LSB executable 80386


cd: sh commands text
chgrp: ELF 32-bit LSB executable 80386
chmod: ELF 32-bit LSB executable 80386
chown: ELF 32-bit LSB executable 80386
chroot:ELF 32-bit LSB executable 80386
cksum: ELF 32-bit LSB executable 80386
clear: Bourne/Korn shell commands text

3.2.3 Vizualizarea fişierelor text


Pentru a vizualiza fişiere de tip text (ASCII) vom prezenta în cele ce
urmează comenzile cat, more, head şi tail.

49
UNIX

Comanda cat
Comanda cat (denumirea provine de la concatenate) ne oferă
posibilitatea vizualizării fişierelor text. Deoarece comanda cat afişează rapid
pe ecran conţinutul fişierului respectiv, trebuie să fim pregătiţi să folosim
combinaţiile Ctrl+s şi Ctrl+q prezentate anterior sau să folosim comanda
more. Exemplu:
$ cat /home/razvan/.profile
va afişa conţinutul fişierului /home/razvan/.profile pe ecran. În cazul în care
conţinutul fişierului este mai mare decât un ecran, această comandă poate fi
conectată prin pipe cu comanda more astfel:
$ cat /etc/passwd | more
şi astfel se va afişa ecran cu ecran conţinutul fişierului /etc/passwd.
Comanda cat poate fi utilizată şi pentru concatenarea a două sau mai
multe fişiere într-unul singur. În acest caz, sintaxa este următoarea:
$ cat fisier_1 [fisier_2 [fisier_n]] > fisier_complet

Fişierele fisier_1, fisier_2, ..., fisier_n vor fi concatenate într-unul


singur, fisier_complet.

Comanda more
Comanda more oferă posibilitatea vizualizării fişierelor text –
acestea sunt afişate ecran cu ecran. Exemplu:
$ more /etc/passwd
Comanda de mai sus afişează conţinutul fişierului /etc/passwd ecran
după ecran. Pentru defilarea liniilor pe ecran se pot folosi: tasta <SPACE>
pentru defilarea unui întreg ecran, tasta <ENTER> pentru defilarea unei
singure linii şi tasta <q> pentru terminarea afişării.
Observaţie:
Doar acele fişiere care determină defilarea ecranului pot fi editate cu
ajutorul editorului standard UNIX, vi (visual editor) în timpul vizualizării
fişierului prin intermediul comenzii more. O alternativă a comenzii more
este comanda less, considerată de mulţi mai performantă. Această comandă
este disponibilă pe majoritatea distribuţiilor Linux şi UNIX; conţine
funcţionalităţi în plus precum deplasarea înapoi. Spre deosebire de comanda
more începe afişarea fişierului înainte ca acesta să fie încărcat în întregime
în memorie.
50
Administrarea fişierelor şi directoarelor

Comanda head
Comanda head este utilizată pentru afişarea primelor n linii dintr-
unul sau mai multe fişiere. Dacă se omite specificarea numărului de linii, se
afişează în mod implicit primele 10 linii din fişier. Comanda head este utilă
în cazul în care se doreşte vizualizarea rapidă a primelor linii dintr-un fişier,
fără a lua în considerare mărimea acestuia. Sintaxa generală a comenzii este
următoarea:

$ head [-n] fisier(e)

În figura 3.1 este prezentat un listing al comenzii head -5 lista (sunt


afişate primele 5 linii ale fişierului lista).

Figura 3.1 Exemplu de listing al comenzii head

Comanda tail
Comanda tail se foloseşte pentru afişarea ultimelor n linii dintr-un
fişier text. În mod asemănător cu comanda head, dacă se omite specificarea
numărului de linii, se afişează în mod implicit ultimele 10 linii din fişier.
Comanda tail este utilă în cazul în care se doreşte vizualizarea rapidă a
ultimelor intrări într-un fişier log de dimensiuni mari.
Utilitarele de backup utilizează frecvent această metodă de a scrie
rezultatele într-un fişier log care ne arată pentru ce fişiere a fost făcută copia
de siguranţă şi când. Ultima linie dintr-un astfel de fişier log conţine, de
regulă, numărul total de fişiere care au fost procesate şi mesaje ce indică
dacă procesul de backup s-a încheiat cu succes. Comanda tail poate fi
folosită în două moduri:
$ tail [-n] fisier(e)

sau
$ tail [+n] fisier(e)

51
UNIX

În primul caz sunt afişate ultimele n linii din fişierul specificat, pe


când în cel de-al doilea caz se porneşte afişarea începând cu a n-a linie din
fişier, până la sfârşit. În figura 3.2 este prezentat un listing al comenzii
tail -5 lista (sunt afişate ultimele 5 linii ale fişierului lista).

Figura 3.2 Exemplu de listing al comenzii tail

3.2.4 Comenzi pentru compararea fişierelor


Pentru a vedea dacă două fişiere sunt diferite sau nu putem folosi fie
comanda wc, fie comanda diff. Dacă specificul comenzii wc este de fapt
altul, pentru a vedea într-adevăr diferenţele dintre cele două fişiere trebuie
să utilizăm comanda diff. Să prezentăm în continuare cele două comenzi.

Comanda wc
Comanda wc provine de la "word count" şi este utilizată pentru a
determina numărul de caractere, cuvinte sau linii conţinute într-un fişier
text. De asemenea, comanda mai poate fi utilizată atunci când dorim să
comparăm două fişiere. Apelată fără opţiuni, comanda wc ne oferă
informaţii despre numărul de linii, cuvinte word, octeţi din fişierul
specificat. Folosind opţiunile comenzii, se poate specifica să se afişeze doar
ce ne interesează. Formatul general şi opţiunile sunt:
Opţiunile sunt:
-l numără liniile
$ wc [-optiune] fisier(e) -w numără cuvintele
-c numără octeţii
-m numără caracterele
Spre exemplu, comanda wc –l /etc/passwd poate afişa: 26 passwd,
ceea ce înseamnă că fişierul /etc/passwd conţine 26 de linii. Se pot specifica
mai multe fişiere în cadrul comenzii wc, de asemenea se pot folosi şi
metacaractere. În figura 3.3 este prezentat un alt exemplu unde sunt afişate

52
Administrarea fişierelor şi directoarelor

informaţii referitoare la toate fişierele ce încep cu litera l din directorul


curent de lucru, precum şi un total al acestor informaţii.

Figura 3.3 Exemplu de listing al comenzii wc

Conform exemplului din figura 3.3, fişierul lista conţine 17 linii,


90 de cuvinte şi 610 octeţi, fişierul lista1 are 10 linii, 83 de cuvinte şi
556 octeţi iar fişierul lista2 are 7 linii, 7 cuvinte şi 54 de octeţi. În total, cele
3 fişiere însumează 34 de linii, 180 de cuvinte şi 1220 de octeţi.

Comanda diff
Comanda diff (difference) este utilizată pentru a compara două
fişiere text şi a găsi diferenţele dintre acestea. Formatul general al comenzii
este:

$ diff [optiune] fisier1 fisier2

Opţiunile acestei comenzi sunt:


ƒ -i ignoră diferenţele între litere mari şi litere mici (B este totuna
cu b etc.);
ƒ -c oferă o comparare detaliată şi produce un listing pe larg a
diferenţelor, începând cu identificarea fişierelor şi datele de
creare a respectivelor fişiere.

53
UNIX

Figura 3.4 Exemplu pentru comanda diff


Folosită cu opţiunea -c, comanda diff afişează informaţiile detaliate
ale celor două fişiere, apoi o linie cu asterisk-uri (*) şi liniile din fişierul
fisier1, cu un semn minus (-) în faţa liniilor ce diferă de fisier2. Acelaşi
format de afişare este valabil şi pentru fisier2, cu semnul + în faţa liniilor
diferite faţă de cele din fisier1. În figura 3.4 avem un exemplu de afişare
detaliată pentru comanda diff, utilizată cu opţiunea -c. Este afişat conţinutul
celor două fişiere cu ajutorul comenzii cat, apoi listingul comenzii diff.

Observaţie.
Dacă nu există diferenţe între cele două fişiere (dacă cele două
fişiere sunt identice) atunci comanda diff nu va afişa nimic.

54
Administrarea fişierelor şi directoarelor

3.2.5 Comenzi de creare şi ştergere pentru fişiere şi directoare


Înainte de a descrie modalitatea de creare şi ştergere a fişierelor şi
directoarelor în UNIX, să reamintim regulile de stabilire a numelor pentru
fişiere şi directoare. Acestea sunt:
ƒ Lungimea maximă a numelui unui fişier sau director nu poate
depăşi 255 de caractere (cu toate acestea, numele prea lungi nu
sunt recomandate);
ƒ Se recomandă utilizarea caracterelor alfanumerice împreună
cu două caractere non-alfanumerice: liniuţa de unire (semnul
minus -) şi liniuţa de subliniere (caracterul underscore _ );
ƒ Se pot utiliza şi alte caractere non-alfanumerice, dar nu este
recomandat;
ƒ Numele de fişiere conţin de regulă şi o extensie, dar pot avea şi
mai multe extensii.
ƒ Numele directoarelor nu au de regulă extensii, dar acest lucru nu
este interzis.

Crearea fişierelor
De regulă, fişierele şi directoarele sunt create de utilizatorii obişnuiţi
sau de către administratorul sistemului, dar există şi multe aplicaţii care
creează fişiere. O modalitate de a crea un fişier nou, fără conţinut este aceea
de a utiliza comanda touch. Sintaxa comenzii este următoarea:

$ touch fisier1 fisier2 … fisierX

Cu ajutorul comenzii touch se pot crea chiar mai multe fişiere


simultan, având în vedere că uneori trebuie să existe un anumit fişier înainte
de a adăuga informaţii în el. Comanda touch poate fi utilizată şi pentru a
actualiza data şi ora ultimului acces la fişier, care va reseta bitul archive,
făcând posibil din nou backup-ul (utilitarele de backup analizează de regulă
bitul archive pentru a actualiza copia fişierului respectiv sau nu).
În figura 3.5 avem un exemplu prin care am creat 5 fişiere cu
comanda touch. Dacă fişierele respective nu există, comanda touch le va
crea, dacă există, va fi modificată doar data şi ora timpului de
acces/modificare.

55
UNIX

Figura 3.5 Exemplu de utilizare a comenzii touch

Crearea directoarelor
În UNIX putem crea directoare cu ajutorul comenzii mkdir. Sintaxa
comenzii este următoarea:

$ mkdir dir1 dir2 … dirX

Cu ajutorul comenzii mkdir se pot crea chiar mai multe directoare


simultan, cu condiţia să avem drepturi (de acces) pentru a crea directoarele
respective. În caz contrar, vom primi un mesaj de eroare de genul:

$ mkdir /usr/Test
mkdir: Failed to make directory “/usr/Test”; Permission
denied

Observaţie.
Pentru a crea o structură de directoare pe mai multe nivele trebuie să
utilizăm comanda mkdir cu opţiunea -p. De exemplu, pentru a crea structura
de directoare dir1/dir2/dir3 din directorul curent, vom utiliza comanda:

$ mkdir dir1/dir2/dir3

Considerând alt exemplu, comanda

$ mkdir –p /home/razvan/temp/seminar_unix

creează un nou director intitulat /home/razvan/temp/seminar_unix,


precum şi toate directoarele intermediare necesare. Spre exemplu, dacă
există doar directorul /home/razvan, atunci vor fi create directoarele temp
(ca subdirector al directorului /home/razvan) şi seminar_unix (ca
subdirector al directorului /home/razvan/temp).

56
Administrarea fişierelor şi directoarelor

Ştergerea fişierelor
În UNIX putem şterge fişiere cu ajutorul comenzii rm. Sintaxa
comenzii este următoarea:

$ rm [-i] fisier(e)

Fişierele şterse prin comanda rm sunt permanent şterse, fără a exista


posibilitatea recuperării (doar când folosim o interfaţă grafică recuperarea
mai este posibilă), deci trebuie să fim atenţi cum folosim această comandă.
Prin utilizarea opţiunii -i avem posibilitatea de a fi atenţionaţi înainte de
ştergerea fişierelor.
Exemple:

$ rm student.txt Se şterge fişierul student.txt


$ rm stud1 stud2 stud3 Se şterg fişierele stud1, stud2 şi
stud3
$ rm -r TEMP Se şterge directorul TEMP,
împreună cu tot conţinutul său

Ştergerea directoarelor
Ştergerea directoarelor se face fie cu comanda rm -r nume_director,
fie cu rmdir. Pentru a putea însă şterge un director cu comanda rmdir,
trebuie ca directorul sau directoarele respective să fie goale, adică să nu
conţină nimic, nici un fişier sau subdirector. În caz contrar, vom obţine un
mesaj de eroare, ca în figura 3.6. Comanda rmdir poate fi folosită astfel:

$ rmdir dir1 dir2 … dirX


Directoarele specificate
trebuie să fie goale

Figura 3.6 Mesaj de eroare în cazul încercării de ştergere a unui director


care nu este gol cu comanda rmdir

57
UNIX

Pentru a şterge directoare care nu sunt goale, trebuie să utilizăm


comanda rm -r, astfel:

$ rm -r [i] dir1 dir2 … dirX

3.2.6 Comenzi de copiere, redenumire, mutare şi redirectare


Copierea fişierelor
Copierea fişierelor şi directoarelor se face cu ajutorul comenzii cp. O
operaţie uzuală este aceea de copiere a unui fişier. Spre exemplu, dacă
trebuie modificat un fişier, vom face o copie de siguranţă a acestuia apoi
vom face modificările necesare. Dacă dorim să ne întoarcem la versiunea
anterioară a fişierului, putem folosi copia făcută mai înainte.
De regulă, putem copia un fişier în două moduri: fie îl copiem în
acelaşi director cu alt nume, fie îl copiem în alt director cu acelaşi nume
(putem să specificăm şi un nume diferit, totuşi). Pentru a copia fişierul în
acelaşi director vom folosi comanda:
$ cp [-i] fis_sursa fis_destinatie

unde fis_sursa este numele fişierului sursă iar fis_destinatie


reprezintă noul nume. În exemplul din figura 3.7 este copiat fişierul student
cu noul nume student.bak. Am obţinut în acest mod o copie a fişierului
student.

Figura 3.7 Fişierul student este copiat cu noul nume student.bak


în directorul curent

Pentru a copia un fişier în alt director (păstrând acelaşi nume pentru


fişier) vom folosi comanda:

$ cp [-i] fis_sursa dir_destinatie

58
Administrarea fişierelor şi directoarelor

unde fis_sursa este numele fişierului sursă iar dir_destinatie


reprezintă numele directorului destinaţie. În acest caz numele fişierului se
păstrează, însă se poate specifica şi alt nume. Comanda:

$ cp razvan temp

va copia fişierul razvan în subdirectorul temp (dacă acesta există).


De asemenea, comanda:

$ cp /usr/razvan/student

va copia fişierul student din directorul /usr/razvan în directorul


curent, iar

$ cp /usr/razvan/student /usr/serban

va copia fişierul student din directorul /usr/razvan în directorul


/usr/serban.
Comanda cp poate fi, de asemenea, folosită împreună cu
metacaracterele * şi ? pentru a se copia mai multe fişiere deodată. Spre
exemplu, în figura 3.8 se copiază toate fişierele al căror nume începe cu
litera l în subdirectorul temp.

Figura 3.8 Toate fişierele al căror nume încep cu l sunt copiate


în subdirectorul temp

Observaţie.
Comanda cp nu ţine cont de existenţa fişierului destinaţie ce urmează
a fi copiat. De aceea, pentru a preveni ştergerea accidentală a vechilor
fişiere, este util să folosim opţiunea -i (interactive) ca măsură de securitate.
Utilizarea acestei opţiuni face ca atunci când fişierul destinaţie există să fim
întrebaţi dacă dorim copierea peste fişierul vechi sau nu, ca în figura 3.9.

59
UNIX

Figura 3.9 Utilizarea comenzii cp cu opţiunea -i


pentru prevenirea ştergerii accidentale a fişierelor

Copierea directoarelor
Copierea directoarelor se face cu ajutorul comenzii cp -r (recursive).
Folosirea opţiunii -r face ca directoarele să fie copiate cu tot cu
subdirectoare, dacă este cazul. Pentru copierea un director vom folosi
comanda:
$ cp -r[i] dir_sursa dir_destinatie

unde dir_sursa este numele directorului sursă iar dir_destinatie este


numele directorului destinaţie. În figura 3.10 este prezentat un exemplu de
copiere a unui director folosind comanda cp -r.

Figura 3.10 Utilizarea comenzii cp -r pentru copierea unui director


Redenumirea fişierelor
Atât fişierele cât şi directoarele pot fi redenumite cu ajutorul
comenzii mv (move). Această comandă poate fi utilizată cu două sensuri:
pentru a redenumi un fişier în cadrul unui director sau pentru a muta (nu
copia!) un fişier dintr-un director în altul. Redenumirea unui fişier se face
astfel:

$ mv [-i] fis_sursa fis_destinatie

60
Administrarea fişierelor şi directoarelor

unde fis_sursa este numele vechi al fişierului iar fis_destinatie este


noul nume al fişierului. Dacă directorul este acelaşi atât pentru sursă cât şi
pentru destinaţie, este vorba despre o redenumire; dacă directoarele diferă,
avem de-a face cu o mutare a fişierului dintr-un director în altul. În figura
3.11 avem un exemplu de redenumire: fişierul lista este redenumit în
lista_nou.

Figura 3.11 Redenumirea fişierului lista în lista_nou

Pentru a muta un fişier în alt director, vom folosi următoarea sintaxă:

$ mv [-i] fis_sursa dir_destinatie

unde se specifică numele fişierului sursă (fis_sursa) şi numele


directorului destinaţie (dir_destinatie). În figura 3.12 fişierul lista2 este
mutat în directorul temp.

Figura 3.12 Mutarea fişierului lista2 din directorul curent


în subdirectorul temp

Redenumirea directoarelor
Redenumirea unui director se face astfel:
$ mv [-i] dir_sursa dir_destinatie

61
UNIX

unde dir_sursa reprezintă vechiul nume al directorului iar


dir_destinatie este noul numele al directorului. În figura 3.13 avem un
exemplu de redenumire a unui subdirector în cadrul aceluiaşi director (dir1
este redenumit în dir_nou).

Figura 3.13 Redenumirea unui subdirector în cadrul aceluiaşi director

În figura 3.14 este considerat un exemplu în care subdirectorul nu


este redenumit în cadrul aceluiaşi director, ci este mutat în alt director
(directorul dir_nou este mutat în directorul temp).

Figura 3.14 Mutarea unui subdirector în alt director

Alte exemple:
Se redenumeşte fişierul
$ mv student.txt student.doc student.txt cu noul nume
student.doc

62
Administrarea fişierelor şi directoarelor

Se redenumeşte fişierul
student în temp (de remarcat
$ mv student temp
este faptul că, dacă temp este
un director, fişierul student va
fi mutat în acel director).

$ mv student /home/serban/temp Se mută fişierul student în


directorul /home/serban/temp
Observaţie.
Ca şi în cazul comenzii cp, este bine să prevenim ştergerea
(rescrierea) accidentală a vechilor fişiere şi directoare, prin utilizarea
opţiunii -i (interactive) ca măsură de securitate. Utilizarea acestei opţiuni
face ca atunci când un fişier sau director cu acelaşi nume există să fim
întrebaţi dacă dorim suprascrierea sau nu, ca în figura 3.15. Vom introduce
n (no) dacă nu dorim acest lucru sau y (yes) dacă dorim suprascrierea.

Figura 3.15 Exemplu de utilizare a comenzii mv -i

Redirectarea intrărilor şi ieşirilor


Sistemul de operare UNIX oferă o facilitate deosebit de utilă de
redirectare a intrărilor sau/şi ieşirilor unei comenzi. Toate operaţiile ce se
desfăşoară într-un computer au intrări şi/sau ieşiri. De exemplu, tastatura
reprezintă fişierul standard de intrare (denumit stdin) iar monitorul
(ecranul) reprezintă fişierul standard de ieşire (denumit stdout). Toate
comenzile UNIX au un fişier standard de intrare (input) şi un fişier standard
de ieşire (output). Intrarea este, de regulă, tastatura iar ieşirea este, de
regulă, ecranul monitorului. Cu ajutorul operatorilor de redirectare se pot
schimba însă aceste setări implicite.
Redirectarea ieşirii se face utilizând operatorul >, redirectarea
intrării se face cu ajutorul operatorului < iar redirectarea erorilor (mesajelor
de eroare obţinute în urma rulării unor comenzi) se face prin utilizarea
combinaţiei 2>. În continuare este prezentat formatul general al redirectării.
Fişierul aflat după simbolul de redirectare poate fi un fişier text sau un fişier
asociat unui dispozitiv (fişier device), având în vedere că în UNIX toate
dispozitivele sunt definite sub formă de fişiere. Spre exemplu, ecranul

63
UNIX

monitorului este referit de fişierul /dev/console, unitatea de floppy disc este


referită de /dev/fd iar imprimanta de /dev/lp. Formatul general pentru
redirectare este:
$ comanda simbol_redirectare fisier

unde comanda este numele comenzii, simbol_redirectare este unul


dintre simbolurile de redirectare existente iar fisier este numele unui fişier
text sau numele unui fişier generic asociat unui dispozitiv UNIX.

Redirectarea intrării
Conform formatului general de mai sus, pentru redirectarea intrării
unei comenzi vom folosi următoarea sintaxă:
$ comanda < nume_fisier

Un exemplu de utilizare al redirectării intrării este:

$ mail serban < lista

În care utilizatorului serban i se trimite prin email conţinutul fişierului


lista.

Redirectarea ieşirii
Redirectarea ieşirii unei comenzi determină crearea unui nou fişier în
modul următor:
$ comanda > nume_fisier

Un exemplu de utilizare al redirectării ieşirii este:

$ ls > lista

în care este creat fişierul lista ce conţine ieşirea comenzii ls. Exemplul este
prezentat şi în figura 3.16.

64
Administrarea fişierelor şi directoarelor

Figura 3.16 Exemplu de redirectare a ieşirii

Observaţie.
Pentru a redirecta ieşirea unei comenzi poate fi folosit şi operatorul
>> care are acelaşi efect cu > dar este folosit pentru a adăuga ieşirea la
sfârşitul unui fişier existent, în loc de a suprascrie fişierul.

Redirectarea erorilor
Redirectarea erorilor generate de comenzi este utilă atunci când se
doreşte analiza lor. Adminstratorii de sistem şi programatorii fac acest lucru
atunci când scriu shell-scripturi de administrare. Pentru a redirecta fişierul
standard de eroare, se foloseşte ca operator de redirectare combinaţia 2>,
astfel:

$ comanda 2> nume_fisier


Se creează un nou fişier sau se
suprascrie peste cel existent.

În exemplul din figura 3.17 am redirectat erorile în fişierul eroare,


care este afişat în continuare. Eroarea provine din faptul că am încercat să
copiem un director cu comanda cp fără opţiunea -r.

Figura 3.17 Exemplu de redirectare a erorilor

65
UNIX

Observaţie.
Am putea include aici şi operatorul pipe ( | ) care se foloseşte atunci
când ieşirea unei comenzi este redirectată ca intrare pentru o altă comandă.
Efectul folosirii unei „secvenţe pipe” este acela al scrierii unui mic program,
deoarece se pot înşirui până la 20-30 de comenzi într-o astfel de secvenţă
pipe. Spre exemplu, dacă dorim afişarea ecran cu ecran a fişierelor din
directorul curent (atunci când avem multe fişiere în director) putem folosi
secvenţa pipe următoare:
$ ls -la | more

Crearea de legături
Pentru a salva spaţiu pe disc şi a nu face o copie a unui fişier, de
multe ori putem crea o legătură (link) către acesta. În acest mod putem
accesa fişierul specificat şi din alte locaţii de pe hard disk. Crearea de astfel
de fişiere tip legătură este utilă atunci când mai mulţi utilizatori trebuie să
lucreze asupra aceluiaşi fişier (un proiect la care lucrează o echipă de
programatori, de exemplu) sau atunci când se doreşte o referinţă la un fişier
utilizându-se un nume mai scurt. Comanda folosită este comanda ln (link)
iar formatul general al este:

$ ln fisier fisier_nou

Comanda anterioară crează un link pentru fişierul fisier în directorul


curent, cu numele fisier_nou; pentru crearea unei legături în alt director
decât cel curent, vom folosi formatul:

$ ln fisier director/fisier_nou

Observaţie.
Atunci când este creat un fişier, este creată o legătură dintre director
şi acel fişier. Numărul de legături pentru fiecare fişier este de cel puţin 1
(referinţa proprie). Numărul de legături este afişat în cea de-a doua coloană
a listingului comenzii ls -l. De fiecare dată când este creată o legătură către
un fişier, numărul de legături ale acelui fişier este incrementat. În figura
3.18 avem un exemplu în care este listat numărul de legături (1) către
fişierul test, este creată o legătură către fişierul test şi apoi vedem că
numărul de legături a devenit 2.

66
Administrarea fişierelor şi directoarelor

Figura 3.18 Exemplu de creare a unei legături cu comanda ln

Observaţie.
Pentru a şterge un fişier de tip legătură se utilizează aceeaşi comandă
rm, care va şterge legătura către fişier dar nu şi fişierul original. Odată cu
ştergerea fişierului de tip link, numărul de legături al fişierului original este
decrementat cu 1.

3.3 Comenzi legate de hard discuri şi partiţii

În ultimii ani hard discurile au devenit deosebit de încăpătoare astfel


încât majoritatea sistemelor de operare le pot administra cu relativă uşurinţă.
Majoritatea sistemelor de fişiere existente au o dimensiune minimă a
fişierelor şi un număr maxim de fişiere şi/sau directoare ce pot fi stocate pe
un dispozitiv fizic, ceea ce vine în contradicţie cu dimensiunile din ce în ce
mai mari ale hard discurilor.
Pentru a rezolva această problemă, sistemele de operare moderne
oferă posibilitatea împărţirii discului fizic în mai multe discuri virtuale ce se
numesc partiţii. Şi sistemele de operare Windows şi Macintosh oferă
posibilitatea de partiţionare logică a discurilor, cu toate că, pentru sistemele
desktop (la care aceste două sisteme de operare sunt folosite cu predilecţie)
această facilitate (şi, pe de altă parte, protecţie) nu este atât de imperioasă ca
în cazul unui sistem utilizat pe post de server într-o reţea. Lucrurile stau
diferit în lumea UNIX faţă de cea Windows; astfel, într-un sistem UNIX pot
exista sute de discuri virtuale (transparent faţă de utilizatorul obişnuit) – iar
directorul home se poate afla pe două sau trei partiţii diferite. Unul dintre
motivele acestei strategii UNIX este acela că programele ce rulează au
deseori tendinţa de a lăsa în urma lor fişiere de tip log (iniţializare) sau temp
(temporare) care pot umple în mod inutil spaţiul liber de pe hard disc. Mai
mult însă, trebuie să avem o grijă deosebită când este vorba despre spaţiul
liber de pe hard disc deoarece sistemul de operare UNIX îşi diminuează
considerabil performanţele atunci când duce lipsă de spaţiu liber. În acest
sens trebuie avute permanent în vedere dimensiunile partiţiilor, fişierele

67
UNIX

de dimensiuni mari şi modalitatea de control al acestora înainte de a deveni


o problemă pentru sistemul de operare.
Pentru controlul asupra gradului de ocupare a sistemului de fişiere
putem utiliza comenzile df, du şi dfspace.
Comanda df
Comanda df provine de la „disk free” şi este utilizată pentru a
determina mărimea spaţiului liber de pe disc. Exemple:
# df
Simplul apel al comenzii df va afişa spaţiul liber (blocuri şi i-noduri)
pentru toate sistemele de fişiere montate. Chiar şi acest apel al comenzii ne
oferă o serie de informaţii utile:
Filesystem 1k-blocks Used Available Use% Mounted on
/dev/sda5 380791 108116 253015 30% /
/dev/sda1 49558 7797 39202 17% /boot
/dev/sda3 16033712 62616 15156608 1% /home
none 256436 0 256436 0% /dev/shm
/dev/sdb1 17245524 1290460 15079036 8% /usr
/dev/sdb2 253871 88384 152380 37% /var

# df /
Afişează spaţiul liber din directorul specificat: / (root).
# df -kvi
Afişează spaţiul liber pe toate sistemele de fişiere montate măsurat în
kilobiţi şi i-noduri.
Comanda df diferă câte puţin de la o variantă UNIX la alta. Există o
serie de opţiuni cu care această comandă poate fi apelată, în funcţie şi de
varianta sistemului de operare, cum spuneam mai înainte. Spre exemplu,
Linux are opţiunea –h pentru această comandă, care produce următorul
output:
# df –h
Filesystem Size Used Avail Use% Mounted on
/dev/sda5 372M 106M 247M 30% /
/dev/sda1 48M 7.7M 38M 17% /boot
/dev/sda3 21G 62M 20G 1% /home
none 250M 0 250M 0% /dev/shm
/dev/sdb1 22G 1.3G 20G 8% /usr
/dev/sdb2 248M 87M 148M 37% /var

Formatul folosit aici este mai inteligibil: putem vedea cu uşurinţă că


atât /home cât şi /usr au un spaţiu neutilizat de câte 20 GB!.
Spre deosebire de alte variante UNIX, Solaris 8 are o comandă df ce
ne oferă informaţii foarte diferite de output-ul de mai sus. Comanda df se

68
Administrarea fişierelor şi directoarelor

concentrează mai degrabă asupra fişierelor şi a sistemului de fişiere decât


asupra discurilor şi a spaţiului utilizat de pe acestea:
# df
/ (/dev/dsk/c0d0s0 ): 827600 blocks 276355 files
/boot (/dev/dsk/c0d0p0:boot): 17584 blocks -1 files
/proc (/proc ): 0 blocks 1888 files
/dev/fd (fd ): 0 blocks 0 files
/etc/mnttab (mnttab ): 0 blocks 0 files
/var/run (swap ): 1179992 blocks 21263 files
/tmp (swap ): 1179992 blocks 21263 files
/export/home (/dev/dsk/c0d0s7 ): 4590890 blocks 387772 files

În acest caz este mai greu de observat ce se „întâmplă”; putem


observa însă că informaţiile prezentate sunt, în ordine, următoarele: punctul
de montare, identificatorul dispozitivului, dimensiunea acestuia în blocuri
de câte 1KB şi numărul de fişiere existente pe acel dispozitiv.
Din acest listing nu ne putem da seama însă care este procentul de
spaţiu ocupat pe disc din total; această comandă apelată fără nici o opţiune
nu ne oferă informaţii foarte importante din punct de vedere al
administratorului. Există însă opţiunea –t (totals), care oferă un listing mai
relevant şi informaţii utile unui administrator de sistem:
# df -t
/ (/dev/dsk/c0d0s0 ): 827600 blocks 276355 files
total: 2539116 blocks 320128 files
/boot (/dev/dsk/c0d0p0:boot): 17584 blocks -1 files
total: 20969 blocks -1 files
/proc (/proc ): 0 blocks 1888 files
total: 0 blocks 1932 files
/dev/fd (fd ): 0 blocks 0 files
total: 0 blocks 258 files
/etc/mnttab (mnttab ): 0 blocks 0 files
total: 0 blocks 1 files
/var/run (swap ): 1180000 blocks 21263 files
total: 1180008 blocks 21279 files
/tmp (swap ): 1180000 blocks 21263 files
total: 1180024 blocks 21279 files
/export/home (/dev/dsk/c0d0s7 ): 4590890 blocks 387772 files
total: 4590908 blocks 387776 files

Comanda dfspace
Comanda dfspace este o comandă specifică sistemelor SCO UNIX,
oferind o modalitate de vizualizare a spaţiului liber de pe disc mai uşor de
înţeles faţă de comanda clasică df.

69
UNIX

Comanda du
Pentru a determina spaţiul ocupat de un director din sistemul de
fişiere UNIX se poate folosi comanda du (disk usage). Exemple:
$ du
Apelată fără nici o opţiune, comanda du ne arată spaţiul ocupat de
către directorul curent pe disc, măsurat în blocuri;
$ du -k
Opţiunea –k ne va arăta spaţiul ocupat în blocuri de câte 1KB;
$ du /home/razvan
Această comandă ne prezintă spaţiul ocupat de către subdirectorul
/home/razvan.
$ du –ks /home/razvan/*
Afişează un sumar al fiecărui subdirector din directorul
/home/razvan.
De regulă, comanda du generează un listing destul de lung atunci
când este vorba despre multe fişiere şi directoare existente în directorul
pentru care se face afişarea. Să considerăm următorul exemplu:
12 ./.kde/Autostart
16 ./.kde
412 ./bin
36 ./CraigsList
32 ./DEMO/Src
196 ./DEMO
48 ./elance
16 ./Exchange
1232 ./Gator/Lists
4 ./Gator/Old-Stuff/Adverts
8 ./Gator/Old-Stuff
1848 ./Gator/Snapshots
3092 ./Gator
160 ./IBM/i
136 ./IBM/images
10464 ./IBM
76 ./CBO_MAIL
52 ./Lynx/WWW/Library/vms
2792 ./Lynx/WWW/Library/Implementation
24 ./Lynx/WWW/Library/djgpp
2872 ./Lynx/WWW/Library
2880 ./Lynx/WWW
554 ./Lynx/docs
184 ./Lynx/intl
14 ./Lynx/lib
140 ./Lynx/lynx_help/keystrokes
360 ./Lynx/lynx_help
196 ./Lynx/po
86 ./Lynx/samples
20 ./Lynx/scripts
1110 ./Lynx/src/chrtrans
6848 ./Lynx/src

70
190 ./Lynx/test
13974 ./Lynx
28484 .
Administrarea fişierelor şi directoarelor

Prima valoare de pe fiecare linie reprezintă dimensiunea fiecărui


director. Această dimensiune însumează dimensiunile tuturor fişierelor şi
subdirectoarelor din acel director. Astfel, directorul Lynx are dimensiunea
de 13974, incluzând subdirectorul Lynx/src (6848) care, la rândul său
conţine subdirectorul Lynx/src/chrtrans de dimensiune 1110.
Ultima linie reprezintă dimensiunea totală însumată a fişierelor,
directoarelor şi subdirectoarelor: 28484. Care este unitatea de măsură? Din
păcate, aceasta depinde de implementare; de exemplu, în cazul Linux Red
Hat 7.2, pagina de manual pentru comanda du ne arată că unitatea de măsură
nu este explicit specificată! Există, din fericire opţiunea –k care ne permite
afişarea dimensiunilor în blocuri de câte 1KB, deci liniile următoare:
# du –k | tail –1
28474 .
ne lămureşte că este vorba despre 28474 KB, deci aproximativ
27,8 MB (28474 / 1024).

3.4 Căutarea fişierelor pe disc

În momentul când dorim să căutăm un fişier pe disc este foarte utilă


comanda find. Comanda find este una dintre cele mai puternice comenzi ale
sistemului de operare UNIX. Sintaxa de bază a comenzii este:

$ find cale_de_cautare criteriu_de_cautare [comanda]

Comanda find poate fi folosită pentru a căuta fişiere pe hard discurile


locale sau chiar şi pe sisteme la distanţă. Deoarece operaţia de căutare poate
solicita destul de mult procesorul, trebuie să încercăm să începem căutarea
din directorul cât mai apropiat de fişier; doar în cazul în care nu avem nici
un indiciu legat de posibila localizare a fişierului vom începe căutarea din
rărăcină ( / ).
Putem face căutări ale fişierelor UNIX folosind mai multe criterii de
căutare printre care: numele parţial sau întreg al fişierului, dimensiune, dată,
drepturi de acces, dreptul de proprietate, etc. Calea de căutare specificată în
comandă (conform formatului general de mai sus) poate fi semnul special
tilda (~) ce în UNIX reprezintă directorul home al utilizatorului curent,
punctul ( . ) ce reprezintă directorul curent sau o cale întreagă de directoare,
relativă sau absolută. Ultimul parametru al comenzii find îl reprezintă
comenzi opţionale ce pot fi inserate la sfârşit.
71
UNIX

În mod implicit, opţiunile de căutare sunt tratate ca o cerere „şi”,


astfel încât toate expresiile introduse trebuie să fie prezente (adevărate). De
asemenea, poate fi folosită opţiunea -o (or) între expresii pentru a specifica
criterii de căutare de tip „sau” care sunt adevărate dacă cel puţin unul dintre
criterii este adevărat. Majoritatea expresiilor de căutare necesită o valoare ce
trebuie găsită şi uneori sunt folosite metacaracterele în cadrul argumentelor
comenzii. Tabelul 3.19 ne înfăţişează câteva expresii de căutare; aceste
expresii sunt evaluate de către comanda find ca fiind false sau adevărate.

Criterii de căutare pentru comanda find


Tabelul 3.19
Expresia Semnificaţie Acţiunea
name nume_fisier Căutare după nume Caută toate fişierele cu numele specificat în
nume_fisier.
type tip_fisier Căutare după tip Caută toate fişierele cu tipul specificat de
tip_fisier.
mtime [+|-]n Căutare după Caută toate fişierele a căror modificare este
data/ora ultimei mai veche (+) sau mai nouă (-) decât n zile.
modificări
atime [+|-]n Căutare după Caută toate fişierele a cărui acces este mai
data/ora ultimului vechi (+) sau mai nou (-) decât n zile.
acces la fişier
perm mod Căutare după Caută toate fişierele care satisfac criteriul
permisiuni de acces de permisiuni specificat (folosind notaţia
octală).
size [+|-]n[c] Căutare după Caută toate fişierele care au dimensiunea
permisiuni de acces exactă, mai mare (+) sau mai mică (-) decât
n (n reprezintă blocuri de 512 octeţi, sau
caractere dacă este urmat de c).

Prezentăm în continuare câteva exemple:

Se caută începând din rădăcină


$ find / -name ls -print după nume fişierul ls şi se va afişa
rezultatul căutării (-print)
Se caută din rădăcină fişierul cu
$ find / -name seminar_unix\
-type f -print numele seminar_unix. Dacă este
găsit, se va afişa pe ecran locaţia sa
Se caută începând din directorul
$ find /usr -name hello -type\
f -print usr după nume fişierul hello şi se va
afişa rezultatul căutării

72
Administrarea fişierelor şi directoarelor

Se caută din directorul usr toate


$ find /usr -name “sem*”\
-type f -print fişierele al căror nume începe cu
sem.
Se caută plecând din directorul
$ find ~ -name “*gif”\
-type f -print home toate fişierele al căror nume se
termină cu gif.

În figura 3.20 este prezentat alt exemplu. Se apelează comanda find


fără nici un argument, fapt ce determină afişarea fişierelor din directorul
curent, apoi se caută începând cu directorul curent fişierele al căror nume se
termină în „.bak”, care apoi se şterg, folosindu-se opţiunea interactivă ok.

Figura 3.20 Exemplu mai complex de utilizare a comenzii find


În figura 3.21 este prezentat alt exemplu în care se caută începând cu
directorul curent fişierele deţinute de un anumit utilizator (daemon) şi se
execută comanda ls care este însă redirectată într-un fişier (daemon_files)
pentru a fi accesat mai târziu.

Comanda următoare:

$ find . -name “rc.conf” -exec chmod o+r ‘{}’ \;

va căuta în directorul curent şi toate subdirectoarele sale toate


fişierele cu numele rc.conf pentru care va executa comanda chmod o+r.
73
UNIX

Argumentul '{}' va insera fiecare fişier găsit în linia de comanda chmod, iar
\; semnifică încheierea liniei de comandă exec. Rezultatul comenzii va fi
acela că toţi utilizatorii vor avea drepturi de citire asupra fişierelor rc.conf.
Un exemplu mai complex de căutare a fişierelor utilizând operatorul
-o îl întâlnim în cazul următor:
$ find /usr/src -not\( -name "a*" -o -name "a.*" \) '{}' \; -print

Această comandă va căuta în directorul /usr/src precum şi în toate


subdirectoarele acestuia toate fişierele, cu excepţia celor de forma „a*” şi
„a.*”. Argumentele implicate aici sunt:
• -not semnifică negarea expresiei ce urmează
• \( semnifică începutul unei expresii complexe
• \) semnifică sfârşitul unei expresii complexe
• -o semnifică o operaţie de sau logic într-o expresie complexă

Figura 3.21 Alt exemplu de utilizare a comenzii find

Comanda următoare:

$ find . -exec grep “infocib.ase.ro” ‘{}’ \; -print

74
Administrarea fişierelor şi directoarelor

va căuta în directorul curent şi în toate subdirectoarele sale şi va


afişa toate fişierele ce conţin şirul de caractere specificat (infocib.ase.ro).
Această comandă poate fi utilă în cazul în care dorim să modificăm şirul de
caractere specificat cu alt şir de caractere pentru toate fişierele dintr-un
director (spre exemplu, putem modifica infocib.ase.ro cu
www.infocib.ase.ro). În acest caz vom redirecta ieşirea către o comandă sed
pentru înlocuirea şirului de caractere.

3.5 Căutarea şirurilor de caractere în fişiere

Comanda grep
Comanda grep (global regular expression print) este folosită pentru
căutarea unor şiruri de caracactere într-unul sau mai multe fişiere sau în
ieşirile generate de comenzi. Şirurile de caractere pot conţine pe lângă
caractere alfanumerice şi spaţii sau diferite semne de punctuaţie, cu condiţia
să fie încadrate de apostrofuri (’’).
De regulă, comanda grep este utilizată ca filtru pentru ieşirile altor
comenzi. Comanda grep face distincţie între litere mari şi litere mici în mod
implicit; dacă dorim să schimbăm această setare implicită, putem folosi
opţiunea -i. Opţiunea -v caută toate liniile ce nu se potrivesc şablonului
specificat. Formatul general al comenzii grep este următorul:

$ grep [optiuni] sir_caractere nume_fisier

unde sir_caractere reprezintă şirul de caractere căutat iar


nume_fisier fişierul în care se va face căutarea.
Vom prezenta în continuare câteva exemple de utilizare a comenzii
grep:

$ grep ‘razvan’ /etc/passwd

Această comandă caută toate apariţiile şirului de caractere "razvan"


în fişierul "/etc/passwd". Toate liniile ce conţin acest şir de caractere vor fi
afişate pe ecran.

$ grep ‘stud’ *

75
UNIX

Această comandă caută toate apariţiile şirului de caractere "stud" în


toate fişierele din directorul curent. Se poate folosi astfel comanda grep în
cazurile în care căutăm un fişier al cărui nume l-am uitat dar ştim un şir de
caractere conţinut de acel fişier. De asemenea, putem specifica opţiunea -n
pentru a afişa şi numărul liniei pe care se află şirul de caractere căutat.
Cunoscând numărul liniei, putem apoi cu un editor de texte să deschidem
fişierul respectiv pentru editare la linia respectivă. În figura 3.22 se caută
şirul de caractere „test” în fişierele din directorul curent. Se găseşte fişierul
lista, ce conţine pe linia 11 şirul de caractere căutat.

Figura 3.22 Utilizarea comenzii grep cu opţiunea -n

Comanda grep poate fi folosită pentru a căuta şiruri de caractere ce


corespund unor şabloane. Metacaracterele ce pot fi utilizate în acest caz
sunt:

. (punctul) Acţionează pe post de orice caracter şi poate fi


utilizat de mai multe ori

* (asterisc) Este folosit pentru zero, unul sau mai multe


caractere
Este folosit pentru a specifica începutul liniei (se
^ (caret) utilizează când se doreşte afişarea liniilor care încep
cu un anumit şir de caractere)
Este folosit pentru a specifica sfârşitul liniei (se
$ (dolar) utilizează când se doreşte afişarea liniilor care se
termină cu un anumit şir de caractere)
Este folosit pentru a specifica shell-ului să trateze
\ (backslash) următorul caracter special după \ în mod normal
[] (paranteze Verifică apariţia unei secvenţe de caractere din
pătrate) domeniul specificat

76
Administrarea fişierelor şi directoarelor

În figura 3.23 avem un exemplu în care comanda grep este conectată


prin pipe comenzii ls:

Figura 3.23 Conectarea comenzii grep prin pipe comenzii ls

Rezultatul comenzii de mai sus va fi afişarea directoarelor din


directorul curent, având în vedere că în listingul comenzii ls -l, caracterul d
la început specifică faptul că fişierul respectiv este director.

3.6 Sortarea fişierelor

În UNIX există posibilitatea de sortare a liniilor unui fişier sau a


ieşirii unei comenzi folosind comanda sort.
Comanda sort
Comanda sort oferă o modalitate rapidă de organizare a datelor în
ordine alfabetică sau numerică. Comanda sort utilizează setul de caractere
ASCII drept ordine de sortare, analizând cuvintele (şirurile de caractere) de
la stânga la dreapta, caracter cu caracter. Comanda sort poate face sortarea
pe mai multe nivele, sau pe anumite câmpuri, având intrare standard şi
oferind ieşire standard. Sintaxa generală a comenzii este următoarea:

$ sort [optiuni] [fisier_intrare]

77
UNIX

În continuare sunt prezentate câteva opţiuni ce pot fi folosite cu


comanda sort:

-n Permite o sortare numerică

(+|-)n
Începe (+) sau se termină (-) cu câmpul ce urmează
după al n-lea separator. Separatorul implicit este spaţiul

-r Inversează ordinea de sortare

-f
Utilizat pentru a ignora diferenţa între litere mari şi
litere mici
În acest caz se utilizează ordinea de dicţionar; sunt
-d comparate doar literele, cifrele şi caracterele white
spaces iar toate celelalte simboluri sunt ignorate
+nM
Sortează primele trei caractere ale câmpului drept
prescurtări ale numelor lunilor anului
-o Rezultatul comenzii va fi stocat în fişierul specificat
nume_fisier de nume_fisier, în loc să fie afişat pe ecran

În exemplul din figura 3.24 se foloseşte comanda sort pentru a


realiza o sortare inversă, numerică, după alt câmp decât cel implicit
(primul). Rezultatul comenzii este afişarea fişierelor al căror nume începe cu
litera e în ordine descrescătoare a dimensiunii lor.

Figura 3.24 Exemplu de utilizare a comenzii sort

78
Administrarea fişierelor şi directoarelor

3.7 Arhivarea şi compresia fişierelor

3.7.1 Comanda tar


Comanda tar (tape archive) poate fi folosită pentru crearea de arhive
pe suporturi magnetice (benzi sau discuri). Poate fi folosită, de asemenea,
pentru crearea arhivelor de uz general pentru transferul fişierelor în reţele,
Internet, etc. Comanda tar poate fi utilizată şi pentru crearea de copii de
siguranţă pentru fişiere, fiind o comandă standard pentru toate versiunile de
UNIX. Dezvoltată iniţial pentru lucrul cu arhive pe bandă magnetică,
comanda tar poate copia însă fişiere oriunde (hard disc, floppy disc sau alte
unităţi de stocare externe).
Comanda tar poate crea o arhivă a unui singur fişier, dar ea este, de
regulă, folosită pentru arhivarea de directoare întregi într-un singur fişier
care va fi folosit mai târziu dacă este cazul.
Observaţie.
Comanda tar nu asigură şi compresia fişierelor în timp ce creează
arhiva (precum utilitarele winzip, pkzip, winrar, arj, ace, etc. pentru PC).
Cele mai întâlnite opţiuni ale comenzii tar sunt c, t şi x. Spre deosebire de
majoritatea comenzilor UNIX, aceste opţiuni nu trebuie neapărat precedate
de semnul minus (-).
Sintaxa generală a comenzii este următoarea:
$ tar functie [modificator] [fis_iesire] nume_fis |nume_dir

Funcţiile comenzii tar sunt următoarele:


ƒ c (create) - este utilizată pentru a crea o arhivă dintr-un singur
fişier sau director sau din mai multe fişiere sau directoare;
ƒ t (table of contents) - este utilizată pentru a vedea un tabel cu
conţinutul arhivei. Acest tabel reprezintă un listing cu fişierele ce
compun fişierul arhivă de tip tar;
ƒ x (extract) - este utilizată pentru a extrage fişiere dintr-o arhivă şi
a le separa din nou. Fişierul arhivă tar există şi după această
extragere.
Cei mai utilizaţi modificatori ai funcţiilor sunt:
ƒ f (file) - permite specificarea unui fişier tar pentru creare (c),
extragere (x) sau vizualizarea tabelei de conţinut (t);
ƒ v (verbose) - execută comanda în modul „vorbăreţ” care permite
să vedem rezultatele detaliate ale comenzii tar pe măsură ce
aceasta rulează.

79
UNIX

Prezentăm în continuare câteva exemple:

$ tar cvf /dev/rct0 /home

Comanda anterioară va crea o arhivă de tip tar pe dispozitivul


/dev/rct0 (bandă magnetică), copiind toate fişierele şi subdirectoarele din
directorul /home.

$ tar cvf /dev/fd0 /home/razvan

Această comandă va crea o arhivă tar pe discheta /dev/fd0, copiind


toate fişierele şi subdirectoarele din directorul /home/razvan.

$ tar cvf /tmp/home.tar /home

Comanda anterioară va crea o arhivă de tip tar în fişierul


/tmp/home.tar, copiind tot conţinutul directorului /home.

$ tar tvf dir.tar

Această comandă permite vizualizarea tabelului cu conţinut al


arhivei specificate, în modul verbose, ce afişează în detaliu caracteristicile
fişierelor, printre care drepturile de acces şi dimensiunea. În figura 3.25 este
prezentat listingul obţinut în urma execuţiei comenzii anterioare.

3.7.2 Comanda compress


O operaţie frecventă pe un sistem UNIX este aceea de a arhiva
fişierele care nu au fost folosite o perioadă îndelungată de timp şi apoi a le
compresa pentru a reduce spaţiul ocupat pe hard disc. În acest sens, se poate
folosi comanda compress. Toate fişierele, inclusiv cele arhivate cu comanda
tar, pot fi compresate (sau comprimate). Operaţia de compresie
(comprimare) a fişierelor este o operaţie deosebit de utilă deoarece reduce
spaţiul ocupat pe hard disc şi în acelaşi timp face ca fişierele comprimate să
fie disponibile pentru o utilizare ulterioară.

80
Administrarea fişierelor şi directoarelor

Compresia fişierelor pe un sistem UNIX poate reduce dimensiunea


unui fişier cu 20% până 80%, în funcţie de tipul fişierului. Dacă utilitarul de
compresie ajunge la concluzia că fişierul nu poate fi comprimat sau nu
există nici o reducere în dimensiune a fişierului, atunci fişierul va rămâne
nemodificat. Fişierele comprimate cu comanda compress sunt înlocuite cu
un fişier cu acelaşi nume cu cel original, dar care are extensia .Z (atenţie,
litera mare Z). Comanda compress oferă posibilitatea compresiei mai multor
fişiere o dată, precum şi folosirea metacaracterelor pentru specificarea mai
multor fişiere.
Prezentăm în continuare câteva exemple:

$ compress /tmp/home.tar

Această comandă comprimă fişierul /tmp/home.tar, înlocuindu-l cu


un fişier denumit /tmp/home.tar.Z.

Figura 3.25 Exemplu de utilizare a comenzii tar

$ compress -v install.log

81
UNIX

Această comandă este apelată cu opţiunea verbose şi va afişa numele


fişierului de intrare (install.log), numele fişierului de ieşire (install.log.Z)
precum şi procentul de compresie obţinut.
Observaţie.
Fişierele comprimate sunt considerate fişiere binare, de aceea
conţinutul lor nu poate fi vizualizat folosind comenzile cat sau more.
3.7.3 Decompresia fişierelor
Fişierele compresate pot fi aduse în starea iniţială comprimării prin
utilizarea comenzii duale comenzii compress, uncompress. Deoarece
fişierele comprimate nu pot fi utilizate sub această formă, ele trebuie aduse
în starea de dinaintea comprimării, operaţia purtând numele de
decomprimare sau decompresare. Formatul general al comenzii uncompress
este următorul:

$ uncompress [optiuni] nume_fisier

unde se pot specifica anumite opţiuni şi numele fişierului


(nume_fisier) pe care vrem să îl decompresăm. Nu este neapărat necesar să
specificăm extensia .Z, având în vedere că această comandă caută automat
fişierul cu extensia implicită .Z. De asemenea, se pot decompresa mai multe
fişiere o dată, folosind metacaracterele * şi ?.
Pentru a vizualiza conţinutul unui fişier comprimat fără a face
efectiv decomprimarea, se poate folosi opţiunea -c. De exemplu, pentru a
vizualiza conţinutul unui fişier comprimat cu numele install.log.Z putem
folosi comanda (am utilizat comanda more pentru cazul în care fişierul
decomprimat va apărea pe mai multe ecrane):

$ uncompress -c install.log.Z | more

3.7.4 Comanda jar


Comanda jar (Java archive) este asemănătoare cu comanda tar, dar
înglobează şi compresia fişierului într-un singur pas. Fişierele arhivate sunt
compresate prin intermediul aplicaţiei Java jar într-o arhivă de acest tip.
Utilitarul jar reprezintă un instrument de arhivare bazat pe formatele de
compresie zip şi zlib. Comanda jar este o comandă standard pentru sistemul
de operare Solaris dar este disponibil pe orice sistem ce are instalat maşina

82
Administrarea fişierelor şi directoarelor

virtuală Java (JVM - Java Virtual Machine). Sintaxa generală a comenzii


este foarte asemănătoare cu aceea a comenzii tar. Opţiunile disponibile
pentru comanda jar sunt următoarele:

c Creează o nouă arhivă jar

t Listează conţinutul fişierului jar

x Extrage fişierele specificate din arhiva jar

F
Specifică fişierul jar (/tmp/fisier.jar) sau banda
magnetică (/dev/rmt/x)
V Specifică execuţia în modul verbose

3.7.5 Alte utilitare pentru compresie


Există o sumedenie de utilitare pentru compresie/decompresie ce pot
fi folosite pe UNIX. Cele mai populare sunt utilitarele gzip, gunzip şi gzcat
(ce derivă din proiectul GNU şi sunt disponibile pe majoritatea versiunilor
de UNIX). Există, de asemenea, şi programele zip şi unzip (similare
variantelor pentru Windows) care pot fi utilizate pentru compresia, respectiv
decompresia fişierelor. Prezentăm în continuare utilitarele gzip, gunzip şi
gzcat.

Comanda gzip
Sintaxa generală a comenzii este:

$ gzip [-acdfhlLnNqrtvV19] [-S sufix] [nume_fisier ...]

Utilitarul gzip foloseşte algoritmul de compresie Lernel-Ziv (LZ77)


pentru a reduce dimensiunea fişierelor specificate în comandă. Pentru
fiecare fişier specificat, fişierul original este şters şi înlocuit cu varianta sa
compresată ce are acelaşi nume cu fişierul original căruia i se adaugă
extensia .gz. Fişierul compresat are aceleaşi proprietăţi referitoare
la modurile de acces, permisiuni, data/ora de acces, data/ora ultimei
modificări, precum fişierul original. Atunci când nu se specifică numele
unui fişier pentru a fi compresat, gzip citeşte de la intrarea standard,
compresează şi afişează la ieşirea standard.

83
UNIX

Pentru decompresie, se pot folosi comenzile gzip -d, gunzip sau


gzcat. Atunci când decompresia se face (cu gzip -d sau gunzip) pe un alt
sistem de fişiere decât cel iniţial, există posibilitatea ca numele original al
fişierului să fie un nume invalid pentru noul sistem de fişiere. În acest caz,
utilitarul de decompresie creează un fişier cu un nume valid pentru noul
sistem de fişiere.

Comanda gunzip
Programul gunzip citeşte fiecare fişier ce începe cu numele specificat
şi are o extensie de tipul .gz, .z, .Z, .bz2, apoi şterge fişierul şi îl înlocuieşte
cu varianta decomprimată a fişierului, înlăturându-i extensia. Sintaxa
generală pentru gunzip este:

$ gunzip [-acfhlLnNqrtvV] [-S sufix] [nume_fisier ...]

De asemenea, comanda gunzip recunoaşte şi extensiile .tgz şi .taz ca


prescurtări ale extensiilor .tar.gz şi .tar.Z. Aceste două extensii sunt folosite
de gzip atunci când fişierele comprimate au extensia .tar. În plus, gunzip
poate decomprima fişiere comprimate cu alte comenzi, precum: zip,
compress, compress -H, pack sau mkszip, recunoscând automat tehnica de
compresie folosită. Există însă o serie de limitări la decompresie; de
exemplu, fişierele comprimate cu zip pot fi decomprimate doar dacă ele
conţin un singur fişier care a fost comprimat cu metoda „deflation”. În caz
contrar, trebuie folosit utilitarul unzip pentru decompresie.

Comanda gzcat
Programul gzcat are un comportament asemănător comenzii gunzip -c.
Acest program poate decompresa fişierele specificate la linia de comandă,
fie, dacă nu sunt specificate fişiere (sau în loc de numele fişierelor apare
liniuţa -), intrarea este standard input. Sintaxa generală pentru gzcat este:

$ gzcat -fhLV [nume_fisier...]

Algoritmul (Lempel-Ziv) de compresie utilizat de gzip este identic cu


cel folosit de utilitarele zip şi pkzip. Procentul de compresie depinde de tipul
fişierului comprimat, dar de regulă este superior celui obţinut de comanda
compress ce foloseşte metoda LZW sau de comanda pack ce foloseşte
84
Administrarea fişierelor şi directoarelor

metoda de compresie Huffman. Din punct de vedere al vitezei de execuţie,


gzip --fast este similară cu comanda compress. gzip modifică (îl comprimă)
fişierul specificat, chiar dacă rezultatul are o dimensiune mai mare decât
fişierul iniţial. Semnificaţia opţiunile comenzilor gzip, gunzip şi gzcat sunt
prezentate în tabelul 3.26.

Opţiuni pentru comanda gzip

Tabelul 3.26
Opţiunea Semnificaţie
-a (--ascii) Foloseşte modul text ASCII Caracterele sfârşit de linie (end-of-
line) sunt convertite folosind convenţii locale. Pe sistemele
Windows, gzip converteşte CR+LF în LF atunci când
comprimă fişierul. La decompresie, gzip -d şi gunzip
converteşte LF înapoi în CR+LF.
-c (--stdout) Scrie rezultatul produs către standard output şi lasă fişierul de
intrare nemodificat.
-d (--decompress) Decomprimă fişierul specificat
-f (--force) Determină forţarea compresiei/decompresiei chiar dacă fişierul
are mai multe legături, dacă fişierul output există deja sau dacă
datele comprimate sunt citite sau scrise la un terminal.
-h (--help) Afişează informaţii de ajutor
-l (--list) Afişează informaţii despre fiecare fişier comprimat.
-L Afişează informaţii despre licenţa gzip
-n (--no-name) Nu salvează implicit folosind numele fişierului iniţial
-N (--name) Atunci când fişierele sunt compresate, se salvează totdeauna
numele şi informaţiile fişierului iniţial, astfel încât la
decompresie, numele fişierului iniţial este restaurat. Această
opţiune se foloseşte pe sisteme ce au reguli stricte privind
lungimea fişierului.
-q (--quiet) Suprimă toate mesajele de avertisment
-r (--recursive) Acţionează pe structura directorului recursiv (inclusiv
subdirectoarele)
-s sufix Modifică extensia implicită .gz în extensia specificată în sufix.
-t (--test) Face un test de integritate a fişierului comprimat
-v (--verbose) Afişează informaţii adiţionale pentru fiecare fişier în parte,
cum ar fi numele şi procentul de reducere a dimensiunii

85
UNIX

Exemple
Putem determina dimensiunea fişierului necomprimat cu o comandă
de genul:

$ gzcat fisier.Z | wc -c

Atunci când utilizăm opţiunea -l în conjuncţie cu opţiunea -v, se


afişează informaţii complete, de genul:

method: -metoda de compresie folosită

crc: -crc-ul pe 32 de biţi pentru datele necompresate

date/time -data şi ora fişierului necompresat

Cu ajutorul comenzii gzcat putem citi un fişier compresat cu gzip


fără a realiza efectiv decompresia, ca în exemplul următor:

$ gzcat carte
cap1
cap2
cap3

Compresia mai multor fişiere

Putem concatena mai multe fişiere comprimate. În acest caz, gunzip


va extrage toate fişierele din fişierul rezultat prin concatenare. De exemplu:

$ gzip -c fisier1 > fiscat.gz


$ gzip -c fisier2 >> fiscat.gz

După crearea fişierului comprimat fiscat.gz, comanda:

$ gunzip -c fiscat.gz

86
Administrarea fişierelor şi directoarelor

este echivalentă cu:

$ cat fisier1 fisier2

Dacă unul dintre fişierele cu extensia .gz sunt stricate, celelalte


fişiere pot fi recuperate (fişierul stricat este înlăturat). Putem îmbunătăţi
nivelul de compresie prin comprimarea tuturor fişierelor împreună, în loc de
a le comprima individual şi apoi concatena rezultatele. De exemplu:

$ cat fisier1 fisier2 | gzip > fiscat.gz

ne va oferi o mai bună compresie decât în cazul:

$ gzip -c fisier1 fisier2 > fiscat.gz

87
4
1. Servicii de reţea
SERVICII
DE REŢEA

Două dintre cele mai utilizate servicii de reţea în UNIX sunt NFS şi
ARPA. Serviciile NFS (Network File System) reprezintă servicii de reţea ce
permit partajarea de directoare în reţea. ARPA este rezultatul unei
combinaţii între „servicii ARPA” şi „servicii Berkeley”. Serviciile ARPA
oferă suport pentru comunicaţiile dintre sisteme ce rulează sisteme de
operare diferite, în timp ce serviciile Berkeley oferă suport doar pentru
sisteme ce rulează sub UNIX. În continuare sunt prezentate cele mai
cunoscute comenzi ARPA-Berkeley.

4.1 Servicii ARPA

4.1.1 Serviciul telnet

telnet – reprezintă una dintre cele mai folosite metode de conectare


la un sistem aflat la distanţă. Comanda telnet utilizează pentru comunicaţie
protocolul cu acelaşi nume şi este o alternativă pentru o altă comandă
similară, rlogin. Exemplul următor prezintă modalitatea de stabilire a unei
conexiuni telnet cu un computer la distanţă (numele computerului este
infocib):
Comentarii

$ telnet infocib Comanda de iniţializare a unei


comunicaţii telnet cu serverul infocib
Connected to infocib. Mesajul primit ca urmare a stabilirii
AIX version 5 infocib conexiunii pe serverul infocib

login: stud Login cu nume de utilizator stud

password: Se introduce parola

Welcome to infocib – rs6000 aix 5L Mesajul de întâmpinare de pe server

$ Prompter-ul AIX de pe infocib

88
UNIX

4.1.2 Serviciul ftp

ftp – protocolul de transfer de fişiere FTP (File Transfer Protocol),


reprezintă cea mai folosită metodă pentru transferul de fişiere de pe un
computer pe altul. Se poate utiliza pentru transferul de fişiere între orice tip
de staţii de lucru sau servere (Windows, UNIX, etc.). În exemplul următor
se va copia fişierul test.file de pe serverul infocib pe staţia locală. Fişierul
test.file se află în subdirectorul tmp al directorului home pentru utilizatorul
stud.

Comentarii

$ ftp infocib Introducerea comenzii ftp

Connected to infocib.
Mesajul de stabilire a conexiunii cu
Infocib FTP server (version 5) ready
serverul

Se cere introducere numelui de login -


Name: stud
se introduce numele de utilizator stud

Se afişează un mesaj prin care se


specifică faptul că utilizatorul stud
Password required for stud.
trebuie să se autentifice prin
introducerea parolei

Password: Se introduce parola


User stud logged in.
Remote system type is UNIX.
Mesajul de întâmpinare de pe server
Using binary mode to transfer files.

ftp>cd tmp Intrăm în subdirectorul tmp


CWD command successful
ftp>get test.file
Lansăm comanda get pentru a copia
PORT command successful
fişierul test.file
Opening BINARY mode data
connection for test.file
Transferul fişierului a fost făcut cu
Transfer complete.
succes.
3305 bytes received în 0.03 seconds
ftp> bye
Goodbye. Închiderea conexiunii ftp.

$ Apariţia prompter-ului de pe server.

89
Sertvicii de reţea

Prezentăm în continuare o listă cu cele mai utilizate comenzi ftp:

Comanda Explicaţii

ascii Setează tipul de transfer al fişierelor la ASCII (se vor transfera


fişiere ASCII de pe un sistem pe celălalt). Aceasta este setarea
implicită.

binary Setează tipul de transfer al fişierelor la binar (se vor transfera


fişiere binare de pe un sistem pe celălalt). Pentru copierea
fişierelor de pe sisteme UNIX pe sisteme non-UNIX este bine să
se utilizeze acest mod de transfer.

cd Modifică directorul curent de lucru pe calculatorul de la distanţă.

dir Listează pe ecran conţinutul directorului curent de pe calculatorul


de la distanţă. Listarea se poate face într-un fişier dacă se
specifică un nume de fişier.

get Comanda este utilizată pentru a copia un fişier de pe calculatorul


de la distanţă pe calculatorul local.

lcd Modifică directorul curent pe calculatorul local.

ls Listează pe ecran conţinutul directorului curent de pe calculatorul


de la distanţă.

mget Comanda este utilizată pentru copierea mai multor fişiere de pe


calculatorul de la distanţă.

put Cu ajutorul comenzii put se copiază fişierul specificat de pe


calculatorul local pe calculatorul de la distanţă.

mput Cu această comandă se copiază mai multe fişiere de pe


calculatorul local pe calculatorul de la distanţă.

quit/bye Se închide conexiunea ftp cu calculatorul de la distanţă.

90
UNIX

4.1.3 Servicii Berkeley

Comanda rlogin
Comanda rlogin (remote login) oferă posibilitatea conectării la un
sistem UNIX de la distanţă. Pentru a ne conecta de pe computerul local pe
computerul infocib, vom utiliza comanda:

$ rlogin infocib

În continuare, dacă se cere o parolă, cei doi utilizatori (cel de pe


sistemul local şi cel de pe sistemul de la distanţă) nu sunt echivalenţi pe cele
două sisteme. Dacă nu se cere nici o parolă, atunci ei sunt echivalenţi.
Comanda rlogin se poate utiliza şi astfel:

$ rlogin nume_sistem -l nume_utilizator

în care se poate specifica numele de utilizator (nume_utilizator) de


pe sistemul de la distanţă (al cărui nume este nume_sistem) la care se face
conectarea.

Comanda rcp
Comanda rcp (remote copy) este utilizată pentru a se copia fişiere şi
directoare de pe un sistem UNIX pe alt sistem UNIX. Pentru a copia fişierul
/tmp/test.file de pe computerul local pe computerul infocib, vom utiliza
comanda:

$ rcp infocib:/tmp/test.file /tmp/test.file

Comanda remsh
Comanda remsh (remote shell) este utilizată atunci când suntem
conectaţi la un sistem UNIX şi dorim să rulăm o comandă pe alt sistem
UNIX. Rezultatele comenzii sunt afişate local. În exemplul de mai jos
putem vizualiza conţinutul fişierului test.file aflat pe serverul infocib
folosind comanda more:

$ remsh infocib more /tmp/test.file

În acest caz trebuie ca utilizatorii de pe cele două sisteme să fie


echivalenţi (să aibă acelaşi nume şi aceeaşi parolă).
91
Sertvicii de reţea

Comanda rwho
Comanda rwho (remote who) este utilizată pentru a determina
utilizatorii conectaţi la alt sistem UNIX. Pentru ca această comandă să
funcţioneze este necesară rularea daemonului rwhod. Există şi alte comenzi de
tip „r” (remote) care diferă între ele în funcţie de varianta de UNIX utilizată.

4.1.4 Maparea numelor staţiilor din reţea

Un lucru important de configurat în reţea îl reprezintă modalitatea de


recunoaştere şi mapare a numelor staţiilor din reţea. În acest sens există trei
metode:
ƒ BIND (Berkeley Internet Named Domain)
ƒ NIS (Network Information Service)
ƒ Fişierul /etc/hosts
Modalitatea cea mai simplă şi cea mai uzitată este aceea de
implementare a numelor staţiilor folosind fişierul /etc/hosts. Acest lucru se
întâmplă mai ales pentru reţele locale restrânse, ce au un număr mic de staţii
de lucru. În reţele mari este utilizat sistemul DNS (Domain Name Server)
care rezolvă maparea numelor staţiilor de lucru, utilizând BIND pentru a
determina adresa pornind de la nume.
Sistemul BIND funcţionează pe baza modelului client/server, astfel
încât în momentul în care un client doreşte adresa unei staţii aceasta este
oferită de către serverul BIND. Utilizarea sistemului BIND conduce la
performanţe mai bune pentru menţinerea informaţiilor legate de nume
deoarece datele sunt stocate doar în câteva locuri şi nu pe fiecare sistem în
parte (ca în cazul fişierului /etc/hosts). Staţiile client folosesc un fişier
/etc/resolv.conf pentru configurarea programului resolver (care determină
adresa folosind numele). Serverul de nume şi adresa IP a sa reprezintă
elementele cheie în rezolvarea mapării adreselor. Configurarea sistemelor
DNS şi BIND este sarcina administratorului de reţea.

Fişierul /etc/hosts
Acest fişier conţine informaţii despre alte sisteme cu care suntem
conectaţi în reţea. Informaţiile din fişier reprezintă adresa Internet a fiecărui
sistem, numele sistemului şi alte alias-uri pentru acesta. Dacă fişierul
/etc/hosts este modificat pentru a conţine numele sistemelor din reţea atunci
se poate folosi comanda rlogin pentru a accesa alt sistem. O linie din fişierul
/etc/hosts arată în felul următor:

<adresa_ip> <nume_oficial> <alias>

92
UNIX

Fişierul /etc/hosts.equiv
Acest fişier este utilizat în cazul în care se doreşte utilizarea
comenzii rlogin fără ca utilizatorii să fie nevoiţi să introducă o parolă atunci
când se conectează la un alt sistem. Totuşi, acest lucru presupune un mare
risc de securitate şi din această cauză acest procedeu nu este prea des
utilizat.
Numele de login ale utilizatorilor trebuie să fie aceleaşi pe ambele
sisteme pentru ca fişierul /etc/hosts.equiv să permită utilizatorilor să se
conecteze fără a introduce o parolă. Fişierul /etc/hosts.equiv trebuie să
conţină numele staţiilor din reţea de pe care se doreşte conectarea, separat
fiecare nume pe câte o linie din fişier.

Fişierul /.rhosts
Fişierul /.rhosts reprezintă alternativa fişierului /etc/hosts.equiv
pentru superuser. Dacă se face conectarea ca root, putem avea aceleaşi date
stocate în /.rhosts ca cele din /etc/hosts.equiv. Acest lucru presupune însă o
mare breşă de securitate în sistem şi nu este recomandat a fi utilizat.
Utilizarea fişierelor /etc/hosts, /etc/hosts.equiv şi /.rhosts conduce la
posibilitatea utilizării comenzilor ARPA ftp şi telnet, precum şi a
comenzilor Berkeley rcp, remsh, rlogin şi rwho.

4.1.5 Alte comenzi pentru lucrul în reţea

Comanda ping
Una dintre cele mai folosite comenzi de reţea este comanda ping.
Aceasta determină existenţa unei conexiuni între două entităţi din reţea.
Comanda ping (Packet InterNet Groper) trimite un pachet ecou ICMP către
staţia specificată o dată la fiecare secundă. În funcţie de varianta de UNIX
utilizată, comanda ping poate diferi de la un sistem la altul, mai ales în ceea
ce priveşte modalitatea afişării rezultatelor pe ecran atunci când comanda
este apelată fără nici o opţiune. În timp ce unele variante afişează rezultate
detaliate despre conexiune, unele variante afişează doar un mesaj de tipul:
„conexiunea este activă”.
Pe un sistem UNIX AIX putem specifica intervalul la care se trimit
pachetele, precum şi dimensiunea şi numărul de iteraţii. Putem considera

93
Sertvicii de reţea

spre exemplu următoarea comandă, în care pachetele se trimit la un interval


de 3 secunde cu dimensiunea pachetului de 4096 octeţi de 8 ori:
$ ping –I 3 venus 4096 8

PING venus: 4096 data bytes


4096 bytes from venus (193.226.34.143): icmp_seq=0. time=8. ms
4096 bytes from venus (193.226.34.143): icmp_seq=1. time=9. ms
4096 bytes from venus (193.226.34.143): icmp_seq=2. time=8. ms
4096 bytes from venus (193.226.34.143): icmp_seq=3. time=9. ms
4096 bytes from venus (193.226.34.143): icmp_seq=4. time=9. ms
4096 bytes from venus (193.226.34.143): icmp_seq=5. time=8. ms
4096 bytes from venus (193.226.34.143): icmp_seq=6. time=8. ms
4096 bytes from venus (193.226.34.143): icmp_seq=7. time=8. ms
----venus PING statistics----
8 packets transmited, 8 packets received, 0% packet loss
round-trip (ms) min/avg/max = 9/9/15

Comanda ping este utilizată pentru depistarea manuală a


eventualelor disfuncţiuni în reţea şi nu se recomandă a fi folosită în mod
continuu deoarece generează mult trafic în reţea.

Comanda netstat

Această comandă este utilizată pentru a determina diverse informaţii


legate de rutarea din reţea. Opţiunea –r ne va afişa tabela de rutare iar
opţiunea –n poate fi folosită pentru a afişa adresele IP din reţea. Altă opţiune
este -v pentru afişarea de informaţii adiţionale legate de rutare, cum ar fi
masca de subreţea. În exemplul următor comanda netstat este apelată cu
opţiunea –nr:
# netstat –nr

Routing tables
Dest/Netmask Gateway Flags Refs Use Interface Pmtu
127.0.0.1 127.0.0.1 UH 0 133563 lop0
4136
10.1.1.10 10.1.1.10 UH 0 356
lan0 4136
10.1.1.110 10.1.1.110 UH 0 0
lan1 4136
10.1.1.0 10.1.1.110 U 2 2
lan0 1300
10.1.1.0 10.1.1.10 U 2 0
lan1 1300
127.0.0.0 127.0.0.1 U 0 0
lop0 4136
default 10.1.1.1 UG 0 0 lan1
1300
#

94
UNIX

Dar să vedem ce semnificaţie au informaţiile afişate mai sus.


Sistemul pe care lucrăm se numeşte a1 şi posedă trei interfeţe. Prima
interfaţă este interfaţa loopback (127.0.0.1) denumită lop0, cea de-a doua
este .10 iar cea de-a treia .110. Următoarele două linii specifică faptul că
destinaţia noastră este 10.1.1.10 care este o reţea ce poate fi accesată prin
intermediul uneia dintre interfeţele de reţea .10 sau .110. Ultima linie
specifică faptul că trebuie trimise pachete la adresa 10.1.1.1 dacă nu se
poate găsi o rută mai directă. Un interes deosebit îl au indicatorii „flags”
prin care se defineşte tipul de rutare, astfel:

ƒ 1=U ↔ rutare către o reţea printr-un gateway care este chiar


sistemul local;
ƒ 3=UG ↔ rutare către o reţea printr-un gateway care este sistem
la distanţă;
ƒ 5=UH ↔ rutare către o gazdă printr-un gateway care este
sistemul local;
ƒ 7=UGH ↔ rutare către o gazdă printr-un gateway la distanţă care
este o gazdă.

Comanda route

Informaţia afişată de comanda netstat provine din tabelele de rutare


ale sistemului care sunt automat create în momentul iniţializării sau în
momentul activării interfeţei de reţea. Rutele către reţele sau gazde ce nu
sunt direct conectate la sistem sunt introduse cu ajutorul comenzii route. În
exemplul următor se modifică indicatorul „Flags” din U în UG:

$ /usr/bin/route add default 193.226.34.64 3

Comanda route de mai sus specifică faptul că dorim să adăugăm o


rută (add), adăugăm o destinaţie (cea implicită - default), un gateway prin
care să facă rutarea. În exemplu s-a considerat adresa IP, dar se poate
specifica şi un nume de reţea. Valoarea 3 corespunde cu valoarea pe care
dorim să o atribuim indicatorului „Flags” (specificăm dacă gateway-ul este
local sau nu).

95
Sertvicii de reţea

Comanda ifconfig

Această comandă ne oferă informaţii suplimentare legate de interfaţa


de reţea. Exemplul următor ne înfăţişează listingul comenzii:

$ /etc/ifconfig eth0
eth0:flags=863<UP,BROADCAST,NOTRAILERS,RUNNING>
inet 193.226.34.141 netmask ffffff00 broadcast 193.226.34.255

Din informaţiile anterioare putem vedea că interfaţa funcţionează


(este „UP”), are adresa IP 193.226.34.141 şi un netmask ffffff00.
De asemenea, comanda ifconfig se poate utiliza pentru configurarea
manuală a interfeţei, specificându-se adresa IP şi masca de subreţea. Spre
exemplu, comanda:

$ /etc/ifconfig eth0 inet 193.226.34.141\


netmask 255.255.255.0

configurează interfaţa de reţea astfel:

ƒ netmask cu valoarea 255.255.255.0 corespunde notaţiei hexa


specificate anterior (fffff00), fiind vorba despre o adresă IP de
clasă C;
ƒ eth0 este denumirea interfeţei ce este configurată;
ƒ inet reprezintă familia adresei;
ƒ 193.226.34.141 este adresa IP a interfeţei.

Observaţie
Caracterul backslash („\”) utilizat mai sus specifică continuarea
comenzii pe linia următoare.

Comanda rpcinfo

Pentru determinarea funcţionalităţii unui sistem putem observa


procesele de tip daemon ce rulează pe acesta. Comanda rpcinfo este utilizată
pentru a genera un apel de procedură la distanţă (RPC – Remote Procedure

96
UNIX

Call) pe un sistem oarecare sau chiar pe sistemul local. Sintaxa comenzii


rpcinfo este:

# rpcinfo -p nume_sistem

Considerăm următorul listing al comenzii rpcinfo –p:

# rpcinfo –p
program vers proto port service
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 777 status
100024 1 tcp 779 status
100021 1 udp 1024 nlockmgr
100005 1 udp 976 mountd
100005 1 tcp 978 mountd

Observăm în lista de mai sus că rulează o serie de procese daemon


pe sistemul curent; spre exemplu, rularea daemon-ului mountd indică faptul
că un server NFS poate monta sisteme de fişiere pe acest computer.

Comanda arp

Cu ajutorul acestei comenzi se poate vizualiza conţinutul memoriei


cache ARP. Corespondenţele între adresele IP şi adresele nivelului 2 MAC
sunt memorate într-o zonă de memorie specială denumită memorie ARP
cache. Maparea adreselor se face la interval de câteva minute; de aceea,
pentru a vizualiza adresele recent mapate existente în memoria ARP cache
putem folosi comanda arp –a:

# arp –a

a1 (10.1.1.10) at 0:10:86:ff:a2:f3 ether


l1 (10.1.1.11) at 0:10:86:ff:a3:b5 ether
tape1 (10.1.1.12) at 0:10:86:ff:65:a3 ether

Se pot introduce manual corespondenţe în memoria cache ARP


utilizând opţiunea –s.

97
Sertvicii de reţea

Comanda nslookup

Această comandă este utilizată pentru determinarea adresei IP a unei


gazde căreia îi cunoaştem numele. Pentru determinarea adresei IP, nslookup
accesează fie fişierul resolv.conf fie /etc/hosts. Exemplul următor ne
prezintă utilizarea fişierului /etc/hosts pentru a determina adresa IP a
sistemului venus:

# nslookup venus
Using /etc/hosts on: venus
Looking up FILES
Name: venus
Address:193.226.34.141
#

4.2 Integrarea cu alte sisteme de operare

De-a lungul anilor au fost dezvoltate o serie de instrumente software


pentru a permite mai multor sisteme de operare să se integreze în aceeaşi
reţea. Flexibilitatea şi puterea sistemului de operare UNIX oferă avantajul
integrării a diferite variante ale acestui sistem de operare faţă de integrarea
cu sisteme non-UNIX. Cu toate acestea, diverse variante UNIX tratează în
mod diferit operaţiuni identice. Există, spre exemplu, diferenţe în controlul
tipăririi între System V şi BSD, diferenţe care complică un pic lucrurile
atunci când vrem să partajăm imprimante într-o reţea cu staţii de lucru sau
servere Solaris, BSD sau Linux.
Datorită realităţilor practice care ne impun ca de multe ori să
integrăm sisteme UNIX cu sisteme ce rulează ceva cu totul diferit
(Windows, NetWare sau MacOS) s-a impus apariţia unor instrumente care
să transforme reţelele eterogene în ceva mai practic şi mai uşor de construit
şi controlat.
Astfel, cu ajutorul programului Samba putem integra sisteme
Windows într-o reţea UNIX (sau sisteme UNIX într-o reţea Windows NT),
putem partaja fişiere şi job-uri de tipărire şi putem gestiona staţiile de lucru
din reţea fie de pe staţiile Windows, fie de pe cele UNIX. De asemenea,
putem folosi netatalk (pentru protocolul de reţea AppleTalk) pentru a putea
face să comunice staţiile UNIX cu cele Macintosh.
Vom aborda în continuare două mari programe cu ajutorul cărora
putem lucra într-o reţea eterogenă, bazată pe staţii de lucru UNIX şi nu

98
UNIX

numai. La început vom prezenta NFS (Network File System) ce acţionează


ca o punte de legătură între diverse variante de UNIX, permiţând montarea
şi partajarea sistemelor de fişiere la distanţă. Vom prezenta în continuare
Samba pentru a vedea cum pot interacţiona în aceeaşi reţea atât clienţi
UNIX cât şi clienţi Windows.

4.2.1 Integrarea diverselor variante UNIX cu ajutorul NFS

Deoarece totul în UNIX este reprezentat sub formă de fişier,


înseamnă că pentru a putea face să comunice două calculatoare pe care
rulează UNIX în aceeaşi reţea, acestea trebuie să fie capabile să partajeze
fişiere. Partajarea fişierelor este o modalitate utilă de a distribui informaţii
unui număr de utilizatori, indiferent de modul de conectare al acestora la
reţea.
În cazul în care există staţii de lucru sau servere specializate în
îndeplinirea anumitor funcţionalităţi (un server de baze de date, spre
exemplu), este deosebit de util ca alte staţii de lucru să poată accesa fişiere
în reţea de pe aceste maşini fără a fi nevoite să copieze fişierele direct pe
propriul hard disc.
Partajarea fişierelor într-o reţea UNIX se poate face prin montarea
directoarelor în reţea astfel încât ele apar ca directoare locale pe staţia de
lucru. Dacă utilizăm staţia de lucru X, se poate monta un director de pe
staţia de lucru Y ca şi cum acesta ar fi local pe staţia X. În momentul în care
nu mai avem nevoie de acel director, el va fi demontat. Aceste lucruri sunt
posibile cu ajutorul sistemului NFS. NFS reprezintă metoda de partajare a
fişierelor între mai multe calculatoare UNIX; el reprezintă un standard, însă
are câteva probleme legate de securitate.

Instalarea şi configurarea NFS

Sistemul NFS face parte integrantă din majoritatea distribuţiilor de


UNIX. De cele mai multe ori el este instalat odată cu instalarea sistemului
de operare. Putem verifica acest lucru uitându-ne în directorul /etc/init.d
pentru un script numit nfs-server; prezenţa acestui script ne spune că
serverul NFS este activ şi că este instalat pe sistem•.


Odată cu instalarea NFS este utilă şi instalarea NIS. Network Information System
acţionează ca o bază de date centralizată ce conţine date administrative importante cum ar
fi parolele şi fişierul /etc/hosts.

99
Sertvicii de reţea

Pentru a putea accesa un sistem de fişiere localizat pe altă staţie de


lucru, trebuie ca pe server să ruleze daemon-ul nfsd iar pe staţia client să
ruleze daemon-ul mountd. În continuare vom considera un exemplu concret.
Să presupunem că maşina pe care dorim să avem directorul se
numeşte saturn. Această maşină este conectată în reţea la un server ce se
numeşte venus. Dorim să exportăm directorul /usr/home de pe calculatorul
venus pe saturn pentru a putea folosi nişte fişiere din acest director. Pentru
acest lucru, trebuie mai întâi să acordăm dreptul pe venus ca acest director
să poată fi montat pe saturn.
Pentru a putea exporta directorul /usr/home sub Linux şi FreeBSD
trebuie să fim logaţi ca root, să deschidem fişierul /etc/exports cu un editor
de text şi să adăugăm următoarea linie:

/usr/home saturn

Această intrare în fişier conţine deci directorul exportat şi numele


calculatorului ce are permisiunea să îl acceseze. Salvăm fişierul şi utilizăm
comanda exportfs la prompter-ul shell. Această comandă face ca toate
directoarele conţinute de /etc/exports să fie disponibile pentru a fi accesate
imediat de către calculatoarele specificate•.
Pe maşina client, saturn, ne vom conecta tot ca root şi va trebui să
montăm directorul pe care dorim să îl accesăm de pe calculatorul venus. În
acest sens vom crea pe saturn un director gol denumit venushome şi apoi
vom lansa comanda
# mount -t nfs venus:/usr/home /venushome

În acest moment, clientul NFS verifică pe serverul NFS instalat pe


venus dacă directorul specificat este accesibil pentru saturn. Deoarece acest
director este specificat în /etc/exports, clientul NFS va monta directorul de la
distanţă în noul punct de montare şi se pot folosi fişierele respective.


Pe un sistem Solaris se utilizează fişierul /etc/dfs/dfstab în locul fişierului /etc/exports, iar
intrările din fişier au forma:
share –o rw=saturn –d “venus usr home” /mn/venus/usr/home
100
UNIX

Montarea automată utilizând fişierul /etc/fstab

Pentru a simplifica montarea repetată a unor directoare la distanţă se


poate folosi fişierul /etc/fstab pentru a monta directoare la distanţă automat
în momentul iniţializării sistemului. Fişierul /etc/fstab conţine o listă cu
toate directoarele ce vor fi montate în momentul iniţializării sistemului, fie
ele locale, fie la distanţă.
Un fişier /etc/fstab obişnuit arată astfel:

LABEL=/ / ext2 defaults 1 1


/dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0
/dev/fd0 /mnt/floppy auto noauto,owner 0 0
none /proc proc defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
/dev/hda4 swap swap defaults 0 0

Utilizarea lui /etc/fstab ne ajută mult la montarea automată a


sistemelor de fişiere şi a directoarelor; ca root putem modifica acest fişier
adăugând directoare pe care le dorim montate automat în momentul
iniţializării sistemului. Sintaxa este următoarea:

nume_dispozitiv punct_de_montare tip_director optiuni dum


pass

O linie în fişierul /etc/fstab conţine astfel: directorul dorit


(nume_dispozitiv), calea unde va fi montat local (punct_de_montare), tipul
de director (tip_director), opţiuni (de exemplu, pentru a putea fi doar citit şi
nu modificat: read-only = ro), numere specifice pentru verificarea de către
sistem (dump şi pass).

101
Sertvicii de reţea

Fişierul /etc/fstab următor conţine încă două linii în plus care


determină montarea în momentul iniţializării sistemului a două partiţii
Windows pe un sistem dual Linux Red Hat/Windows:

LABEL=/ / ext2 defaults 1 1


/dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0
/dev/fd0 /mnt/floppy auto noauto,owner 0 0
none /proc proc defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
/dev/hda4 swap swap defaults 0 0
/dev/hda1 /mnt/c auto defaults 0 0
/dev/hda5 /mnt/d auto defaults
0 0

Aceste partiţii sunt asociate dispozitivelor /dev/hda1 şi respectiv


/dev/hda5 care vor fi montate în directoarele /mnt/c, respectiv /mnt/d.

Securitatea NFS

Se cunosc o serie de breşe în securitatea sistemului NFS, de aceea e


bine să ţinem seamă de acestea atunci când îl utilizăm. Trebuie astfel să ne
luăm o serie de precauţii atunci când configurăm serverul NFS şi montăm
directoarele.
Cel mai important lucru pe care trebuie să îl facem este acela de a
evita instalarea serverului NFS pe o maşină ce are rol de gateway sau de
firewall. Deoarece unul dintre punctele slabe ale NFS este autentificarea
parolelor, este bine să izolăm serverul NFS de eventuale computere ce pot
avea acces la acesta din exteriorul reţelei.
De asemenea, ca în cazul oricărui program ce presupune accesul la
distanţă, se impune instalarea tuturor patch-urilor de securitate existente în
momentul respectiv pentru versiunea de UNIX respectivă. Alte măsuri de
securitate includ:

ƒ Niciodată nu trebuie să apară o referinţă către un localhost în


/etc/exports;
ƒ Este bine să exportăm fişierele ca read-only pentru a exclude
posibilitatea ca cineva din exterior să le modifice;
ƒ Editarea fişierului /etc/exports se va face exportând directoare
către nume de domenii existente şi nu către nume generice de
maşini (de exemplu se preferă folosirea numelui saturn.ase.ro în
locul lui saturn);

102
UNIX

ƒ După modificarea, salvarea şi închiderea fişierului /etc/exports


trebuie rulat imediat programul exportfs.

4.2.2 Integrarea UNIX - WINDOWS

Pentru a face posibilă comunicarea dintre două sau mai multe


computere ce rulează UNIX şi Windows există o serie de produse software.
Fără aceste programe comunicarea dintre un sistem UNIX şi unul Windows
nu ar fi posibilă, datorită protocoalelor diferite de transfer al datelor folosite
de către cele două sisteme de operare. Protocolul utilizat de Windows se
numeşte SMB (Session Message Block), care nu este nativ pentru UNIX.
Două dintre programele ce fac posibilă comunicarea UNIX-Windows sunt
NFS Maestro (Hummingbird Communications Ltd.) şi Samba.
Datorită popularităţii acestuia din urmă, vom analiza în continuare
modul de lucru al programului Samba•. Samba este o colecţie de programe
ce pemite unei maşini UNIX să folosească protocolul SMB şi să partajeze
astfel fişiere între cele două sisteme diferite.
Samba poate să emuleze atribute ale serverelor Windows NT astfel
încât clienţii Windows pot lucra în mod eficient cu serverele. În funcţie de
varianta de UNIX utilizată, Samba se instalează într-un anumit director;
există, de asemenea, câteva distribuţii de Linux care instalează Samba în
mod automat la instalarea sistemului. Pentru a verifica dacă Samba este
instalat sau nu, este suficient să ne uităm în directorul /etc/init.d pentru
subdirectorul /etc/init.d/samba. Dacă acest director există, atunci înseamnă
ca avem Samba instalat pe sistem şi trebuie doar configurat.

Instalarea şi configurarea programului Samba

Programul Samba este prezent de regulă pe CD-urile de instalare ale


sistemului de operare utilizat, dar se poate descărca şi ultima versiune a
produsului de la adresa http://www.samba.org, adresa de Web oficială a
echipei ce se ocupă cu dezvoltarea produsului. Versiunea curentă este 3.0.6
(August 2004). După ce programul Samba este instalat, trebuie configurat;
fişierul de configurare este /etc/samba/smb.conf.


Ghidul complet pentru Samba este „Using Samba”, de Robert Eckstein, David Collier
Brown şi Peter Kelly (O”Reilly&Associates, 1999).

103
Sertvicii de reţea

Deschidem fişierul /etc/samba/smb.conf• cu editorul de text preferat;


este uşor de lucrat cu el deoarece este modular iar secţiunile (modulele) din
fişier sunt clar specificate. Vom avea nevoie de o secţiune [global]
indiferent de mărimea reţelei şi de câte o înregistrare individuală în fişier
pentru fiecare director pe care dorim să îl partajăm cu calculatoare Windows
în reţea. Înregistrarea globală defineşte reţeaua ca un întreg pentru
calculatoarele Windows din reţea. Sintaxa este uşor de înţeles, fişierul de
configurare Samba utilizând expresii în engleză în locul acronimelor şi
abrevierilor. Un fişier minimal de configurare Samba poate arăta astfel:

[global]
workgroup = NETWORK
server string = saturn
encrypt passwords = Yes
update encrypted = Yes
log file = /var/log/samba/log
max log size = 100
socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDUP=8192
dns proxy = No

Fişierul de configurare anterior va seta numele reţelei ca


NETWORK atunci când vom deschide directorul Network Neighbourhood
de pe o staţie Windows (putem folosi orice nume în acest scop). Valoarea
server string este asociată cu numele ce va apărea în directorul ce se va
deschide. Samba stochează datele de iniţializare în fişierul
/var/log/samba/log (implicit) şi va conţine maxim 100 de linii (cele mai
recente). Opţiunea socket defineşte modalitatea de control a datelor
transferate în reţea iar dns proxy specifică dacă serverul va acţiona precum
un proxy server DNS local sau nu.
Odată specificate setările globale, trebuie adăugată o înregistrare
pentru fiecare director pe care vrem să-l partajăm cu staţiile Windows în
reţea. Acest lucru este necesar deoarece nu dorim să partajăm întregul
sistem de fişiere UNIX cu toate calculatoarele Windows din reţea.


Fişierul /etc/samba/smb.conf conţine comentarii specificate într-un mod diferit faţă de alte
fişiere asemănătoare UNIX. Toate liniile ce încep cu caracterul “;” sunt considerate
comentarii, spre deosebire de caracterul “#” utilizat în mod curent.
104
UNIX

Pentru a partaja un anumit director, putem adăuga o înregistrare în


fişierul /etc/init.d/samba/conf cu următoarea structură:

[public]
comment = spatiu public
path = /usr/public
guest ok = yes
writable = yes
printable = no
public = yes

Sintaxa de bază include numele directorului partajat şi câţiva


parametri prin care se specifică modul în care acest director este disponibil
utilizatorilor din reţea. Numele cuprinse între paranteze drepte vor apărea în
directorul Network Neighbourhood din Windows. Linia ce conţine
specificarea căii de acces defineşte calea din sistemul de fişiere UNIX în
timp ce linia guest ok specifică dacă un utilizator are acces la director fără a
introduce un username/parolă. Liniile writable şi printable setează
modalitatea de acces a directorului iar valoarea public specifică dacă
directorul va fi accesibil utilizatorilor.

Utilizarea programului Samba

După ce s-a terminat configurarea fişierului /etc/init.d/samba/conf


putem porni Samba pentru a verifica legăturile din reţea. Repornirea
serverului Samba se face cu comanda:

# /etc/init.d/samba restart

În acest moment serverul Samba este repornit cu configuraţia din


fişierul /etc/init.d/samba/conf şi putem „vedea” staţiile Windows din reţea.
Pe staţiile Windows trebuie să deschidem Control Panel, selectăm Network-
Properties. Verificăm înscrierea corectă a adreselor IP în câmpurile gateway
şi DNS; ele trebuie să corespundă cu cele utilizate de serverul UNIX.
Apăsăm butonul Apply pentru a salva modificările, ieşim din configuraţia
reţelei şi repornim sistemul. Reţeaua definită trebuie să apară în Network
Neighbourhood după repornirea sistemului.
Se poate specifica accesul la directoarele partajate pe sistemul UNIX
astfel încât unele staţii să poată accesa directoarele iar altele nu. Acest lucru
se poate realiza prin includerea în fişierul de configurare a unei linii host
allow ce are sintaxa:

# host allow statie

105
Sertvicii de reţea

unde statie reprezintă fie numele staţiei de lucru, fie adresa IP a


acesteia. Se pot specifica mai multe staţii de lucru ale căror nume pot fi
separate de spaţiu sau virgulă. De asemenea, se poate interzice accesul
anumitor staţii prin host deny:

# host deny statie

Pentru a obţine informaţii despre multiplele configurări posibile ale


programului Samba, este bine să se consulte pagina de manual cu comanda:

$ man smb.conf

Partajarea directoarelor pentru acces personalizat

În afară de faptul că se poate asigura accesul public la directoarele


partajate, uneori este necesar ca aceste directoare să fie accesibile unui
număr limitat de utilizatori. Să considerăm cazul în care dorim să partajăm
directorul /users/personal cu numele personal iar acesta să fie accesibil doar
pentru utilizatorii stud1, stud2 şi stud3. În acest sens, fişierul de configurare
Samba trebuie să conţină următoarele linii:

[personal]
path = /users/personal
valid users = stud1 stud2 stud3
writable = yes
printable = no
public = no
create mask = 0765

Servicii de printare folosind Samba

Unul dintre avantajele reale ale utilizării Samba în reţea este


posibilitatea partajării unei imprimante în reţea, indiferent dacă job-urile de
tipărire provin de la o staţie UNIX sau de la una Windows. În acest sens este
mai bine să se conecteze imprimanta la serverul UNIX deoarece
configurarea imprimantei pentru reţea se face mai uşor aici. Pentru a partaja
o imprimantă ataşată unei maşini UNIX cu staţii Windows din reţea, trebuie
să edităm din nou fişierul de configurare Samba. La sfârşitul înregistrării

106
UNIX

[global] din fişierul /etc/init.d/samba/conf trebuie adăugate următoarele


linii:
printing = bsd
printcap name = /etc/printcap
load printers = yes
log file = /var/log/samba/log
lock directory = /var/lock/samba

Aceste linii specifică tipul de printare (BSD sau System V), locaţia
fişierului /etc/printcap utilizat de modul de tipărire Berkeley şi locaţiile
fişierelor log şi lock. Cea de-a treia linie specifică dacă imprimantele sunt
încărcate în reţea de fiecare dată când este repornit serverul Samba. După ce
am modificat secţiunea [global], trebuie să creăm o nouă secţiune denumită
[printers], ce ajută la configurarea opţiunilor generale de imprimare. Vom
considera în continuare următorul exemplu:

[printers]
comment = all printers
security = server
path = /var/spool/lpd/lp
browseable = no
printable = yes
public = yes
writable = no
create mode = 0700

Aceste setări cuprind: locaţia job-urilor de tipărire, permisiunea


pentru print spool şi imprimantele cărora li se aplică aceste setări. Odată
stabilite setările generale ale imprimantelor din reţea, se poate configura
separat fiecare imprimantă existentă în reţea pentru a avea setări
individualizate. Aceste setări individualizate pentru fiecare imprimantă în
parte conţin numele şi calea imprimantei precum şi informaţii importante
caracteristice fiecărui tip de imprimantă în parte.

107
Sertvicii de reţea

Un exemplu de setare individualizată este următorul:

[ijet]
security = server
path = /var/spool/lpd/lp
printer name = inkjet
public = yes
writable = no
printable = yes
print command = lpr –r –h –P %p %s

Această configurare individuală este specifică fiecărui tip de


imprimantă; pentru a vedea ce tip de comandă trebuie folosită pentru o
imprimantă specifică trebuie consultată pagina de manual pentru comanda
lpd prin comanda man lpd.
După ce am terminat de făcut această configurare, se salvează
fişierul, se iese din editarea sa şi se reporneşte serverul Samba prin
comanda:

# /etc/init.d/samba restart

În continuare, pe staţia Windows deshidem directorul Printers


(Start-Settings-Printers), localizăm noua imprimantă şi facem dublu-click
pe icon-ul acesteia. În ecranul de configurare apărut o selectăm ca
imprimantă de reţea şi avem de ales dacă dorim să fie setată ca imprimantă
impicită sau nu. Apăsăm butonul Ok pentru a salva modificările făcute şi în
acest moment putem selecta imprimanta de reţea din meniul Print al
programelor Windows.

4.2.3 Integrarea Linux – Novell

Posibilităţile inter-operabilităţii Linux-Novell sunt mult mai


restrânse decât acelea ale cooperării UNIX/Linux-Windows. O soluţie de
integrare pentru aceste sisteme de operare o constituie programele ncpfs şi
mars_nwe. Pachetul de instalare pentru ncpfs este disponibil la adresa:
ftp.gwdg.de/pub/linux/misc/ncpfs iar pachetul mars_nwe la adresa:
http://www.compu-art.de/download/mars_nwe.html.
Prezentarea acestor programe nu face obiectul cărţii de faţă, însă cei
interesaţi pot studia instrucţiunile pentru utilizarea programelor la adresa
web http://www.linuxdoc.org/HOWTO/IPX-HOWTO.html.
108
5
1. Editoare de text
Editoare de text

5.1 Introducere

În acest capitol sunt prezentate două editoare de text ce pot fi


utilizate pentru scrierea fişierelor de tip text, implicit pentru scrierea
programelor de tip shell-script. Primul editor este editorul „clasic” al UNIX-
ului, ce se numeşte vi (visual editor - pronunţat ca în englezescul „vee eye”)
iar cel de-al doilea editor de texte este pico. Cu ajutorul acestor editoare de
text vom crea şi/sau modifica fişiere de configurare, fişiere de tip
shell-script sau modifica fişiere de configurare a sistemului legate de reţea,
securitate, administrare etc. Editorul vi face parte integrantă din sistemul de
operare UNIX încă de la începuturile acestuia (anii ’70) şi este disponibil
pentru toate variantele de UNIX. Editorul vi este flexibil şi dispune de o
serie de facilităţi puternice. Editorul pico este editorul popularului utilitarul
de e-mail pine (marcă înregistrată a Universităţii din Washington), fiind
extrem de răspândit în mediul universitar.

5.2 Editorul vi

Editorul vi este folosit pentru a crea sau modifica fişiere text sau
ASCII (American Standard Code for Information Interchange), fiind un
editor bazat pe caracter, parte integrantă a sistemului de operare UNIX.
Editorul vi utilizează ca mediu de afişare ecranul monitorului fără a se putea
utiliza mouse-ul pentru deplasarea cursorului pe ecran; toate deplasările
cursorului se fac cu ajutorul tastelor.
Operaţia de editare în cadrul editorului vi se face prin intermediul
unei memorii tampon sau buffer, iar modificările făcute asupra textului pot
fi salvate sau nu. Editorul vi operează doar asupra fişierelor text simple, fără
caracteristici speciale de formatare (cum ar fi cele create de un editor de
genul Word for Windows). Cu toate că utilizarea vi-ului este destul de
dificilă, utilizatorii experimentaţi şi administratorii de sisteme UNIX trebuie

109
UNIX

să cunoască acest editor. De asemenea, este foarte util şi pentru utilizatorii


mai puţin experimentaţi să cunoască (măcar) funcţionalităţile de bază ale
editorului vi, având în vedere că acesta este parte integrantă a sistemului de
operare UNIX şi multe aplicaţii folosesc acest utilitar în mod implicit.
Pentru administratorii de sistem însă, cunoaşterea editorului vi are o
importanţă majoră, deoarece există cazuri în care acest editor reprezintă
unica posibilitate de editare a fişierelor de configurare a sistemului. Editorul
vi este utilizat şi atunci când se lucrează la distanţă pe alt sistem UNIX,
având în vedere că vi este disponibil pe toate variantele de UNIX.

5.2.1 Modurile de lucru în vi

Pentru editorul vi există trei moduri de lucru: modul comandă,


modul introducere şi modul ultima-linie (last line). Toate comenzile
disponibile în vi pot fi clasificate în unul dintre aceste trei moduri de lucru.
Caracteristicile de bază ale celor trei moduri de lucru sunt următoarele:
ƒ Modul comandă - este modul iniţial de lucru folosit pentru
crearea şi editarea fişierelor, poziţionarea cursorului şi
modificarea textului deja existent. Toate comenzile se introduc
plecând de la acest mod de lucru. Apăsarea tastei <ESC> din
unul din celelalte două moduri de lucru determină trecerea în
modul comandă;
ƒ Modul introducere (sau editare) - este utilizat pentru
introducerea de text. Introducerea unei comenzi de genul i
(pentru inserare), a (pentru adăugare) sau o (pentru deschiderea
unei linii noi) determină trecerea din modul comandă în modul
introducere. Apăsarea tastei <ESC> determină întoarcerea în
modul comandă. Comenzile de introducere sunt date fără a se
apăsa după ele tasta <ENTER>;
ƒ Modul ultima-linie - este folosit pentru salvarea documentului
editat şi pentru ieşirea din vi. Apăsarea tastei „:” determină
trecerea în acest mod de lucru. Apăsarea tastei <ENTER> sau a
tastei <ESC> determină trecerea în modul comandă.
Modul comandă este modul iniţial de lucru al editorului vi. În
momentul pornirii editorului vi, automat se intră în modul comandă. În acest
mod de lucru se pot introduce fie comenzi pentru poziţionarea cursorului în
cadrul fişierului, fie comenzi de editare pentru inserarea de noi caractere sau
modificarea conţinutului deja existent. Pentru a ajunge din modul
introducere în modul ultima-linie sau invers, trebuie să trecem mai întâi prin
modul comandă. Toate comenzile sunt iniţiate din modul comandă.
110
Editoare de text

Apăsarea tastei <ESC> ne plasează mereu în modul comandă, de aceea


putem utiliza tasta <ESC> în cazul în care nu ştim în ce mod de lucru ne
aflăm.
Modul introducere (editare) reprezintă modul în care trebuie să ne
aflăm pentru a introduce text. Pentru introducerea de text, trebuie să dăm o
comandă (prin simpla apăsare a unei taste) cum ar fi i (insert - inserare), o
(open new line - linie nouă) sau a (append - adăugare). Introducerea unei
dintre comenzile anterioare determină trecerea din modul comandă în modul
introducere. În acest mod putem introduce noi caractere în textul iniţial,
apoi putem apăsa tasta <ESC> pentru a ne întoarce în modul comandă.
Modul ultima-linie este modul în care putem ajunge prin apăsarea
tastei “:”, ceea ce determină poziţionarea cursorului pe ultima linie a
ecranului (de aici provine şi denumirea acestui mod de lucru). Modificările
făcute asupra fişierului sunt menţinute într-o memorie tampon până în
momentul în care acestea sunt salvate pe disc. Utilizând modul ultima-linie,
putem salva periodic modificările făcute asupra fişierului fie rămânând în vi,
fie salvând şi părăsind editorul. De asemenea, se poate ieşi din editor fără a
salva modificările făcute. Modul ultima-linie este folosit şi pentru a căuta
şiruri de caractere sau pentru a seta anumite preferinţe de editare.

5.2.2 Deschiderea fişierelor şi comenzi de editare

Editorul vi reprezintă o aplicaţie ce se porneşte de la linia de


comandă UNIX. Ori de căte ori pornim editorul vi, deschidem un fişier.
Putem specifica de la început fişierul ce se va deschide, fie putem deschide
un fişier nou pe care îl vom salva ulterior pe disc. Sintaxa generală a
comenzii vi este următoarea:

$ vi [optiuni] [nume_fisier]

unde atât opţiunile, cât şi numele fişierului pot apărea sau nu.
Paşii de bază în utilizarea editorului vi sunt:
ƒ deschiderea unui nou fişier sau a unuia deja existent;
ƒ introducerea de text nou, modificarea textului deja existent sau
adăugarea de text;
ƒ salvarea fişierului pe disc;
ƒ ieşirea din vi.

111
UNIX

Editorul vi poate fi apelat fie prin comanda vi nume_fisier, fie prin


vedit, care porneşte editorul vi cu modul „show” activat, în care în colţul din
dreapta jos al ecranului se afişează modul de introducere curent (inserare,
adăugare sau line nouă). În modul comandă nu se va fişa nimic. Modul
show poate fi activat prin introducerea comenzii set showmode în dreptul
caracterului „:” din modul ultima-linie.

Comenzi de introducere

O dată cu pornirea editorului vi şi specificarea unui nume de fişier


(sau nu) se poate introduce text în acel fişier. Pentru a introduce text, trebuie
utilizate o serie de comenzi de introducere, comenzi ce sunt apelate din
modul comandă. În modul inserare sau introducere, pentru a folosi alte
comenzi de inserare trebuie să ne întoarcem în modul comandă prin
apăsarea tastei <ESC>. Comenzile de inserare de bază sunt: a (adăugare de
text după cursor), A (adăugare de text la sfârşitul liniei), i (inserare de text
înaintea cursorului) şi o (introducerea unei noi linii sub linia pe care se află
cursorul).

Comenzi de bază pentru poziţionarea cursorului în vi

Tabelul 5.1
Comanda Semnificaţie
j (săgeată în jos) Deplasare o linie în jos
k (săgeată în sus) Deplasare o linie în sus
h (săgeată stânga) Deplasare cu un caracter la stânga
l (săgeată dreapta) Deplasare cu un caracter la dreapta
Tasta <SPACE> Deplasare la dreapta cu un caracter
w Deplasare la dreapta cu un cuvânt
b Deplasare la stânga cu un cuvânt
$ Deplasare la sfârşitul liniei
0 sau ^ Deplasare la începutul liniei
Tasta <RETURN> Deplasare la începutul liniei următoare

112
Editoare de text

Salvarea fişierului şi ieşirea din vi

Pentru a salva fişierul şi a ieşi din editorul vi, trebuie mai întâi să ne
poziţionăm în modul de lucru ultima-linie prin apăsarea tastei „:”. Pentru a
salva fişierul este de ajuns să tastăm :w. Dacă dorim să salvăm fişierul cu alt
nume, vom introduce comanda :w nume_nou_fisier. Pentru a salva fişierul
şi a ieşi din vi, se poate tasta fie :wq, fie ZZ (direct din modul comandă).
Dacă dorim să ieşim din fişier fără să salvăm modificările făcute, putem
introduce comanda :q!. În cazul în care se deschide un fişier read-only
(poate fi doar citit, nu şi modificat) care se doreşte a fi modificat, se pot
salva modificările făcute prin introducerea comenzii :wq! (write-quit). Dacă
se doreşte renunţarea la toate modificările făcute de la ultima salvare, se
poate folosi comanda :e! (erase) care şterge modificările din buffer şi începe
editarea din nou.

Observaţie. În notaţiile de mai sus apariţia caracterului special „:”


semnifică faptul că suntem poziţionaţi în modul de lucru ultima-linie.

Comenzi de bază pentru ştergerea textului în vi

Tabelul 5.2
Comanda Semnificaţie
x Se şterge caracterul din dreptul cursorului
dw Se şterge cuvântul (sau partea din cuvânt) situat la
dreapta cursorului
5dw Se şterg 5 cuvinte la dreapta
dd Se şterge întraga linie pe care este poziţionat cursorul
2dd Se şterg 2 linii începând cu linia curentă
3x Se şterg 3 caractere începând cu cel din dreptul
cursorului

Comenzi de poziţionare a cursorului în vi

Comenzile de poziţionare a cursorului sunt utilizate în modul


comandă în momentul în care se doreşte deplasarea cursorului în cadrul
textului de editat. Pentru poziţionarea cursorului se pot folosi tastele cu
săgeţi direcţionale (stânga-dreapta, sus-jos) dar se pot folosi şi combinaţii
mai rapide de taste. În tabelul 5.1 sunt prezentate o serie de combinaţii de
taste pentru poziţionarea cursorului pe ecran.

113
UNIX

Ştergerea textului în vi

Ştergerea caracterelor deja introduse se face din modul comandă. În


prealabil se face poziţionarea pe caracterele ce se doresc a fi şterse, apoi se
utilizează comenzile de ştergere din tabelul 5.2. Comenzile fac distincţie
între litere mari şi litere mici şi se introduc fără a mai apăsa tasta <ENTER>.

Modificarea textului, anularea comenzii anterioare, copiere


şi alipire de text în vi

În tabelul 5.3 sunt prezentate comenzile de bază pentru modificare,


anularea comenzii anterioare (undo), copiere şi alipire de text. Operaţia de
copiere (copy) se mai numeşte şi yank iar cea de alipire (paste) se mai
numeşte şi put în vi.

Comenzi de bază pentru copiere, alipire,


modificare şi anulare în vi

Tabelul 5.3
Comanda Semnificaţie
cw Are ca efect modificarea cuvântului (sau a părţii din
cuvânt) de la cursor până la sfârşitul cuvântului. Se
poziţionează cursorul în locul de unde dorim să începem
modificarea, apoi se apasă cw, se introduce noul cuvânt şi
se apasă în final tasta <ESC>
5cw Se modifică 5 cuvinte
r Se înlocuieşte caracterul pe care este poziţionat cursorul
cu alt caracter
u Are ca efect anularea ultimei comenzi
dd, apoi p Şterge, apoi alipeşte (paste)
yy, apoi p Copiază, apoi alipeşte
yy Copiază o linie
p Alipeşte linia copiată sau ştearsă sub linia curentă
P Alipeşte linia copiată sau ştearsă deasupra liniei curente

114
Editoare de text

5.3 Editorul pico

5.3.1 Generalităţi

Editorul pico este un editor de texte mai puţin complicat de utilizat


decât editorul vi, fiind integrat în celebrul program de poştă electronică pine,
dezvoltat la Universitatea din Washington.
Uneori, înainte de intrarea în editorul pico trebuie setat tipul de
terminal folosit (dacă se utilizează un terminal vt100, atunci se poate utiliza
comanda export TERM=vt100 pentru setarea tipului de terminal).
Pornirea editorului se face simplu, introducând la linia de comandă:

$ pico [nume_fisier]

5.3.2 Operaţii de bază

Editorul pico oferă o bară de meniu cu cele mai utilizate comenzi în


partea de jos a ecranului, după cum se poate vedea în figura 5.4.

Figura 5.4 Ecranul editorului pico

115
UNIX

Inserarea textului

Pentru a insera text în ecranul de editare pico, se începe pur şi


simplu introducerea textului, fără a se mai introduce altă comandă (ca în
cazul editorului vi). Pico inserează textul introdus de la tastatură la stânga
cursorului, deplasând la dreapta textul existent (dacă acesta există). De
fiecare dată când cursorul ajunge la capătul rândului, caracteristica word
wrap (despărţirea pe linii) a editorului determină deplasarea cursorului la
începutul liniei următoare.

Deplasarea cursorului

Deplasarea cursorului se poate face prin intermediul tastelor


direcţionale (cu săgeţi) sau prin utilizarea combinaţiilor de taste: Ctrl+f
(forward - înainte), Ctrl+b (back - înapoi), Ctrl+n (next - linia următoare)
sau Ctrl+p (previous - linia anterioară).

Ştergerea textului

Caracterul de la stânga cursorului se şterge cu tasta


<BACKSPACE>, <DELETE> sau prin combinaţia Ctrl+h. Pentru a şterge
caracterul de deasupra cursorului se apasă Ctrl+d. Pentru ştergerea liniei
curente se apasă Ctrl+k.

Salvarea documentului

Pentru a salva fişierul pe disc, se apasă Ctrl+o. Pico afişează numele


fişierului curent, iar pentru salvarea fişierului cu alt nume trebuie şters
vechiul nume şi introdus numele dorit, apoi se apasă tasta <RETURN>.

Refacerea ecranului

În cazul în care pe ecranul pico apar caractere ciudate, refacerea


ecranului se face prin combinaţia Ctrl+L.

116
Editoare de text

Ieşirea din program

Pentru a ieşi din editorul pico, se apasă Ctrl+x. Dacă au fost făcute
unele modificări după ultima salvare, pico va afişa un mesaj prin care
întreabă dacă se doreşte salvarea modificărilor. Se poate tasta y (yes - da)
dacă se doreşte salvarea sau n (no - nu) dacă nu se doreşte salvarea.
În momentul introducerii tastei y, pico afişează numele fişierului, care poate
fi modificat.
Comenzile de bază ale editorului pico se găsesc în tabelul 5.5.

5.3.3 Alte facilităţi

Căutarea textului

Căutarea şirurilor de caractere se face în pico începând de la poziţia


curentă a cursorului spre sfârşitul fişierului. Pentru a începe căutarea se
apasă Ctrl+w (whereis - unde este). Pico va cere introducerea textului
căutat. Pentru a începe căutarea, se introduce textul căutat şi se apasă
<ENTER>. Pico va deplasa cursorul în locul în care se găseşte prima
apariţie a textului căutat. Căutarea se poate repeta prin apăsarea din nou a
combinaţiei Ctrl+w.

Alinierea textului

În momentul introducerii de text pe ecran, facilitatea „word wrap” a


editorului pico începe o nouă linie ori de cîte ori este cazul. Uneori trebuie
să aliniem textul introdus; pentru a re-alinia paragraful, trebuzie să
poziţionăm cursorul pe paragraful respectiv şi să apăsăm combinaţia Ctrl+j.
Anularea acestei acţiuni şi aducerea paragrafului la forma iniţială se face
prin combinaţia Ctrl+u.

117
UNIX

Comenzi de bază în editorul pico

Tabelul 5.5
Comanda Efect
Ctrl+f Deplasarea cursorului înainte cu un caracter
Ctrl+b Deplasarea cursorului înapoi cu un caracter
Ctrl+p Deplasarea cursorului pe linia anterioară
Ctrl+n Deplasarea cursorului pe linia următoare
Ctrl+a Deplasarea cursorului la începutul liniei curente
Ctrl+e Deplasarea cursorului la sfârşitul liniei curente
Ctrl+v Deplasarea cursorului înainte cu o pagină
Ctrl+y Deplasarea cursorului înapoi cu o pagină
Ctrl+w Caută text
Ctrl+l Reafişează ecranul pico
Ctrl+d Şterge un caracter de la poziţia cursorului
Ctrl+^ Începe selectarea textului începând cu poziţia cursorului
Ctrl+k Taie (cut) textul selectat sau linia curentă
Ctrl+u Alipeşte (paste) ultimul text tăiat la poziţia cursorului
Ctrl+i Inserează un tab în poziţia cursorului
Ctrl+j Aliniază paragraful curent
Ctrl+t Corectarea semantică
Ctrl+r Inserează (read - citeşte) conţinutul unui fişier la cursor
Ctrl+o Salvează (output) fişierul
Ctrl+g Vizualizarea help-ului
Ctrl+x Se iese din pico, cu salvarea fişierului

Funcţii de tăiere şi alipire

Pentru a tăia o linie cu ajutorul editorului pico trebuie să ne


poziţionăm pe linia respectivă şi să apăsăm Ctrl+k. Ne putem apoi poziţiona
în locul unde dorim alipirea liniei tăiate. Alipirea se face cu ajutorul
combinaţiei Ctrl+u. De asemenea, se pot face tăieri şi alipiri (cut şi paste)

118
Editoare de text

cu blocuri de text (nu doar linii întregi). Această operaţie presupune


parcurgerea următorilor paşi:
1. se mută cursorul pe primul caracter al textului ce urmează a fi
tăiat;
2. se apasă Ctrl+^ pentru a începe marcarea;
3. se utilizează tastele direcţionale pentru a selecta textul dorit;
4. se apasă Ctrl+k pentru tăierea textului;
5. se mută cursorul în locul unde dorim inserarea textului tăiat;
6. se apasă Ctrl+u pentru a alipi textul în noua poziţie.
Inserarea unui fişier text existent

Pentru a insera conţinutul unui fişier deja existent în poziţia


specificată de cursor, se va apăsa Ctrl+r, iar pico va cere introducerea unui
nume de fişier. Se poate introduce direct numele fişierului şi apoi se apasă
<ENTER>, fie se poate apăsa Ctrl+t pentru a selecta un nume dintr-o listă
de fişiere disponibile în directorul curent de lucru. Combinaţia Ctrl+t
determină apariţia unui File Browser, în care putem folosi tastele
direcţionale pentru selectarea fişierului dorit şi apoi se apasă <ENTER>. Se
poate selecta directorul părinte (..) pentru a ne muta un nivel mai sus în
structura de directoare. În afara faptului că se poate insera text, acest
browser de fişiere poate fi folosit pentru a redenumi, şterge sau copia un
fişier. Pentru a ieşi din File Browser se apasă tasta e.

Refacerea editării

În cazul în care o sesiune pico se bochează, pico încearcă să salveze


o copie a fişierului asupra căruia se lucra. Acest fişier salvat de pico se află
în directorul curent de lucru, având extensia .save.

Ajutor

Pentru vizualizarea paginilor de ajutor se va folosi combinaţia


Ctrl+g.

119
1. Shell-uri UNIX

66.1 SHELL-uri UNIX

6.1 Definiţie şi funcţiuni

Parte integrantă a sistemului de operare UNIX, shell-ul este „un


program special utilizat ca o interfaţă între utilizator şi inima sistemului de
operare UNIX, un program denumit kernel”[23]. În timp ce kernelul este
încărcat în memoria calculatorului din momentul iniţializării sale şi până la
oprirea sistemului, toate celelalte programe, inclusiv programele de tip shell
sunt stocate pe disc. Kernelul este, în fapt, administratorul întregului sistem
de operare UNIX; el iniţiază şi controlează procesele, administrează
memoria, sistemul de fişiere, comunicaţiile şi tot ce ţine de resursele
calculatorului.
Shell-ul este un program utilitar ce este pornit în momentul
conectării utilizatorului la sistem, oferind posibilitatea utilizatorilor să
interacţioneze cu kernelul prin interpretarea comenzilor introduse fie direct
de la tastatură, fie prin intermediul unui fişier de comenzi shell, numit fişier
shell-script, sau, pe scurt, script.
În momentul conectării la sistemul UNIX shell-ul îşi ia „atribuţiile”
în primire, îndeplinindu-şi rolul de interpretor al comenzilor introduse de
către utilizator şi care trebuie „înţelese” de către kernel (este echivalentul
interpretorului DOS command.com). În momentul introducerii unei
comenzi, interpretorul de comenzi shell execută următorii paşi:
(1) interpretează sintactic linia de comandă introdusă; (2) interpretează
metacaracterele, redirectările, mecanismele pipe şi controlul job-urilor şi
(3) verifică existenţa comenzii/comenzilor introduse şi dacă acestea există,
sunt executate.
Există posibilitatea utilizării shell-ului în două moduri: interactiv sau
prin intermediul unui fişier script. La început, utilizatorii care învaţă
comenzi şi cum să folosească sistemul UNIX folosesc modul interactiv al
shell-ului. Mai târziu, odată cu utilizarea unor comenzi în mod frecvent, se
impune crearea unor fişiere de comenzi – acele fişiere shell-script. Execuţia
comenzilor prin intermediul unui shell-script înseamnă utilizarea shell-ului
drept limbaj de programare. Prin analogie cu DOS/Windows, fişierele

120
UNIX

shell-script sunt fişiere de tip batch de comenzi, care în sistemul de operare


DOS au extensia .bat.
Fişierele shell-script permit, pe lângă utilizarea mai multor comenzi
ce se execută (de regulă) secvenţial şi facilităţi de programare avansată,
structuri de decizie, ciclare, testare de fişiere, ş.a. Pentru a putea scrie
shell-script-uri trebuie cunoscute nu numai structurile de programare
existente (condiţionale, repetitive, etc.) dar şi comenzile, utilitarele şi
modalitatea de funcţionare a acestora în sistemul de operare UNIX. Printre
programele utilitare existente în UNIX se află şi grep, sed sau awk ce
reprezintă instrumente deosebit de puternice pentru manipularea fişierelor şi
a rezultatelor comenzilor.

6.2 Variante de shell


În UNIX există mai multe implementări ale interpretoarelor de
comenzi, printre care:
ƒ Bourne Shell (sh) – AT&T shell
ƒ C Shell (csh) - Berkeley shell
ƒ Korn Shell (ksh) - include shell-ul Bourne
ƒ Bourne Again Shell (bash - în Linux)
Toate aceste tipuri de shell se comportă aproximativ asemănător
atunci când se lucrează în modul interactiv. Odată cu folosirea acestora ca
limbaje de scripting (programare) apar o serie de deosebiri legate de sintaxă,
eficienţă etc.
Dintre aceste tipuri de shell, shell-ul Bourne este shell-ul standard
UNIX, de aceea vom prezenta pentru început caracteristicile shell-ului
Bourne. De asemenea, majoritatea script-urilor scrise deja pentru
administrarea sistemului (precum rc start şi stop, shutdown) sunt
shell-script-uri Bourne, iar când se lucrează în modul single-user (mod
excepţional de lucru utilizat, de regulă, pentru refacerea sistemului) acesta
este shell-ul utilizat de administratorul sistemului conectat ca root. Shell-ul
Bourne a fost conceput de firma AT&T şi el este rapid, concis şi compact.
Valoarea implicită a prompter-ului este semnul dolar ($) pentru utilizatorii
obişnuiţi şi semnul diez (#) pentru root (utilizatorul privilegiat).
Shell-ul C (csh) a fost dezvoltat la Universitatea Berkeley California
şi a adăugat o serie de noi funcţionalităţi, precum: istoricul comenzilor date
anterior, utilizarea de alias-uri, aritmetică integrată sau auto-completarea
numelor de fişiere şi comenzi. Shell-ul C este preferat atunci când se
utilizează interactiv, dar administratorii preferă să utilizeze shell-ul Bourne
la scrierea shell-script-urilor, deoarece acesta din urmă este mai rapid şi mai

121
Shell-uri UNIX

simplu decât script-urile asemănătoare scrise în C shell. Prompter-ul


implicit în C shell este semnul procent (%) pentru utilizatorul obişnuit.
Shell-ul Korn (ksh) reprezintă o extensie a shell-ului Bourne şi a fost
scris de David Korn de la AT&T. Au fost adăugate o serie de noi
funcţionalităţi faţă de shell-ul Bourne şi cel C. Printre acestea se numără:
istoric editabil al comenzilor, alias-uri, funcţii, aritmetică integrată, controlul
job-urilor, coprocesare şi facilităţi de depanare. Shell-ul Bourne este
aproape 100% compatibil cu shell-ul Korn; de aceea, vechile shell-script-uri
scrise în Bourne shell vor rula şi în Korn shell. Ca şi în Bourne shell,
valoarea implicită a prompter-ului pentru utilizatorul obişnuit este simbolul
dolar ($) şi semnul diez (#) pentru root.

6.3 Scurt istoric


Primul shell cu adevărat important a fost introdus în versiunea V7
(versiunea 7 a variantei AT&T) UNIX în anul 1979 şi a fost denumit după
programatorul Stephen Bourne, creatorul său. Ca limbaj de programare,
shell-ul Bourne se bazează pe limbajul de programare Algol şi a fost folosit
iniţial pentru a automatiza anumite sarcini administrative. Cu toate că acest
shell este foarte popular pentru simplitate şi viteză, are totuşi câteva
minusuri la utilizarea interactivă (lipsa istoricului comenzilor, a alias-urilor
şi a controlului job-urilor).
Pe de altă parte, shell-ul bash (Bourne Again Shell), dezvoltat de
către Brian Fox de la FSF (Free Software Foundation) sub licenţă publică
GNU este shell-ul implicit pentru Linux şi instalat automat începând cu
Solaris 8 (pe servere Sun). Bash oferă o serie de noi facilităţi ce lipsesc în
shell-ul standard Bourne (se păstrează însă compatibilitatea cu acesta),
înglobând şi cele mai bune facilităţi din C shell şi Korn shell. Facilităţile
shell-ului bash sunt: istoric al comenzilor introduse la linia de comandă,
editarea liniei de comandă, controlul job-urilor, funcţii, alias-uri, vectori,
aritmetică integrată (în orice bază între 2 şi 64), structuri de ciclare cu
selecţie pentru creare de meniuri, comanda let etc.
Shell-ul C a fost creat la Universitatea Berkeley, California la
sfârşitul anilor ’70, făcând parte din varianta 2BSD UNIX. Iniţial, shell-ul C
a fost scris de Bill Joy, oferind o serie de facilităţi care nu erau cuprinse în
shell-ul standard, shell-ul Bourne. Shell-ul C este bazat pe limbajul de
programare C, iar atunci când este utilizat drept limbaj de programare
foloseşte o sintaxă asemănătoare cu cea din C. Oferă facilităţile de istoric al
liniei de comandă, alias-uri, controlul job-urilor. Proiectat pe un calculator
puternic, shell-ul C are tendinţa de a fi mai lent pe calculatoare mai puţin
puternice în comparaţie cu shell-ul Bourne.

122
UNIX

Shell-ul TC reprezintă o versiune îmbunătăţită a shell-ului C, având


o serie de noi facilităţi, precum: editarea liniei de comandă, posibilitatea
răsfoirii istoricului, variabile, auto-completarea comenzii, corectare
automată, planificarea job-urilor, etc.
David Korn de la AT&T a inventat shell-ul Korn în 1986 şi a devenit
în mod oficial parte a distribuţiei UNIX SVR4 în 1988. Shell-ul Korn,
compatibil cu shell-ul Bourne, rulează nu numai pe sisteme UNIX, dar şi pe
OS/2, VMS şi DOS. Oferă compatibilitate cu shell-ul Bourne, adăugând
multe facilităţi ale shell-ului C, fiind însă mai rapid şi mai eficient decât
acesta. Shell-ul Korn a avut o serie întreagă de versiuni; cea mai folosită
versiunea a shell-ului Korn o reprezintă versiunea apărută în 1988, cu toate
că şi cea din 1993 este deosebit de populară. Utilizatorii de Linux pot folosi
o versiune free a shell-ului Korn, intitulată The Public Domain Korn Shell
(pdksh), o clonă a shell-ului Korn din 1988. Această versiune este free,
portabilă, compatibilă POSIX. O altă versiune de shell, intitulată Z shell
(zsh) este tot o clonă Korn cu facilităţi din TC shell, scrisă de Paul Falsted şi
disponibilă free pe web.
Datorită popularităţii shell-ului bash şi a importanţei shell-ului
Bourne ca shell clasic, în această carte vor fi prezentate aceste două tipuri de
shell.

6.4 Shell-uri pentru Linux


Cele mai importante variante de interpretoare pentru Linux sunt
Bourne Again Shell (bash) şi TC shell. Aceste shell-uri sunt instalate
implicit pe sistemele Linux, iar începând cu Solaris 8 şi pe sistemele Sun.
odată cu instalarea sistemului de operare Linux se obţine acces la shell-urile
şi programele GNU, nu la shell-urile şi programele standard UNIX. În
Linux, cele mai populare shell-uri sunt bash şi TC shell. Pentru a vedea ce
versiuni de shell-uri sunt disponibile, trebuie cercetat fişierul /etc/shell, iar
pentru a schimba shell-ul implicit în alt shell vom folosi comanda chsh
(change shell), urmată de numele shell-ului dorit. De exemplu, pentru a
modifica shell-ul în shell-ul Korn, vom introduce comanda:

$ chsh /bin/ksh

123
Shell-uri UNIX

6.5 Iniţializarea sistemului şi programul de login

6.5.1 Iniţializarea sistemului

În momentul pornirii sistemului, primul proces apelat este procesul


ce se numeşte init. Fiecare proces are asociat un număr de identificare,
denumit PID (Process Identification). Deoarece init reprezintă primul
proces apelat, acesta are PID=1. Rolul procesului init este acela de a
iniţializa sistemul şi a porni alt proces (getty) ce deschide liniile pentru
terminal, setând standard input (stdin), standard output (stdout) şi fişierul
standard de eroare (standard error - stderr). După aceasta apare un
prompter (de login) pe ecran. Fişierul standard de intrare este în mod normal
tastatura, fişierul standard de ieşire şi cel de eroare sunt reprezentate de
ecranul monitorului.
După ce se introduce un nume de utilizator la prompterul de login, se
cere o parolă pentru autentificare. În acest moment, programul /bin/login
verifică identitatea utilizatorului prin analiza primului câmp din fişierul
/etc/passwd (unde sunt stocate parolele). Dacă numele de utilizator se
regăseşte aici, următorul pas este acela de a verifica dacă parola introdusă
este corectă. După verificarea parolei, programul login defineşte un mediu
iniţial de lucru ce constă din anumite variabile de sistem şi acest mediu de
lucru este transmis shell-ului.
Variabilelor de sistem HOME, SHELL, USER şi LOGNAME le sunt
atribuite valori din fişierul passwd. Variabila HOME reprezintă directorul
home al utilizatorului; variabila SHELL reprezintă numele shell-ului de
login (ultimul câmp din fişierul passwd). Variabila USER şi variabila
LOGNAME reprezintă numele utilizatorului. Printre alte variabile setate
acum este şi variabila PATH, ce reprezintă o colecţie de căi de căutare
pentru comenzile introduse. În momentul terminării execuţiei programului
login, acesta va lansa în execuţie programul găsit în ultimul câmp al
fişierului passwd, corespunzător liniei utilizatorului respectiv. Dacă acest
câmp este /bin/ksh, va fi executat shell-ul Korn; dacă valoarea găsită este
/bin/sh, se va porni shell-ul Bourne. Acest shell poartă denumirea de login
shell.
După pornirea programului shell, se caută diverse fişiere generale de
configurare iar apoi, în directorul home, se caută fişiere de configurare
specifice utilizatorului respectiv. Dacă acestea sunt găsite, se execută.
Fişierele de iniţializare sunt utilizate pentru a adapta mediul uilizatorului la
propriile cerinţe. După ce s-au executat şi aceste fişiere de configurare,
apare un prompter pe ecran. Din acest moment, programul shell aşteaptă
introducerea comenzilor.

124
UNIX

6.5.2 Interpretarea liniei de comandă

În momentul introducerii unei comenzi la prompter, shell-ul citeşte o


linie şi interpretează linia de comandă prin împărţirea acesteia linia în
cuvinte, denumite token-uri. Token-urile sunt separate de spaţii şi caractere
tab, iar linia de comandă se termină cu un caracter special denumit newline.
Acest proces de interpretare al liniei de comandă poartă denumirea de
analiză lexicală.
În următorul pas, shell-ul verifică dacă primul cuvânt introdus este o
comandă internă sau un program executabil pe disc. Dacă este vorba despre
o comandă internă, aceasta va fi executată. În caz contrar, shell-ul va căuta
în lista de directoare din variabila PATH pentru a găsi programul pe disc.
Dacă se găseşte programul, shell-ul va incepe un nou proces (prin apelul
fork) şi apoi va executa programul. După aceasta, shell-ul va aştepta până
când programul îşi încheie execuţia şi apoi, dacă este cazul, va afişa starea
programului care s-a încheiat. În acest moment va apărea prompter-ul şi
întreg procedeul descris mai sus se va relua la introducerea unei noi
comenzi.

6.5.3 Tipuri de comenzi

În momentul execuţiei unei comenzi, aceasta poate fi un alias, o


funcţie, o comandă internă sau un program executabil pe hard disc. Un alias
reprezintă o prescurtare a unei comenzi existente şi se aplică pentru shell-
urile C, TC, Korn şi bash. Funcţiile sunt valabile în shell-urile Bourne
(începând cu versiunea AT&T System V, Release 2.0), bash şi Korn,
reprezentând grupări de comenzi organizate sub forma unor proceduri
separate. Funcţiile şi alias-urile sunt definite în memoria shell-ului.
Comenzile interne reprezintă rutine interne ale shell-ului iar programele
executabile sunt localizate pe hard disc. Shell-ul foloseşte variabila PATH
pentru a căuta programele executabile pe hard disc şi generează un apel fork
de iniţierea a unui proces copil înainte de execuţia comenzii. În momentul în
care shell-ul este gata să execute o comandă, evaluează tipul comenzii în
următoarea ordine:
1) Alias-uri
2) Cuvinte cheie pentru shell
3) Funcţii (în bash)
4) Comenzi interne
5) Programe executabile

Dacă, spre exemplu, comanda introdusă este abc, shell-ul verifică


mai întâi dacă abc este un alias, apoi dacă nu este cuvânt cheie (pentru

125
Shell-uri UNIX

shell). Dacă nu, este o funcţie sau comandă internă? Dacă nici acest lucru nu
este valabil, atunci se verifică (căutând în directoarele specificate în
variabila de sistem PATH) dacă există un program executabil pe hard disc
cu acest nume.

6.5.4 Procese UNIX

Un proces reprezintă o instanţă a unui program aflat în execuţie şi


poate identificat prin numărul său de identificare PID. Cine administrează
procesele în UNIX? Nucleul sistemului de operare (kernel-ul),
administrează şi controlează aceste procese. Un proces este identificat de un
program executabil, date şi stivă, pointer de program şi de stivă, regiştri,
precum şi toate informaţiile necesare pentru ca programul să ruleze. În
momentul pornirii shell-ului, se iniţiează un proces. Shell-ul aparţine unui
grup de procese identificat prin identificatorul PID. Doar un singur grup de
procese are controlul terminalului la un moment dat şi se spune că rulează în
foreground (la suprafaţă). În momentul procesului de login, shell-ul
controlează terminalul şi aşteaptă introducerea unei comenzi la prompter.

Figura 6.1 Exemplu de listing al comenzii ps


Shell-ul poate iniţia şi alte procese. De fapt, în momentul
introducerii unei comenzi la prompter sau atunci când aceasta este apelată
dintr-un shell-script, shell-ul are sarcina să găsească acea comandă intern
(dacă este o comandă internă) sau pe hard disc şi apoi să execute acea
comandă. Acest lucru se face prin intermediul unui apel către kernel,
denumit apel de sistem. Un apel de sistem reprezintă de fapt o cerere
adresată serviciilor kernel-ului şi reprezintă unica modalitate prin care
un proces poate accesa hardware-ul sistemului. Există o serie de apeluri de
sistem ce permit proceselor să fie create, să se execute şi să se termine.
Procesele care rulează la un moment dat pe un sistem UNIX pot fi
vizualizate cu ajutorul comenzii ps (process status). Comanda ps listează
procesele aflate în execuţie. În figura 6.1 avem un exempu de listing al
comenzii ps. Pentru a vizualiza toate procesele ce rulează pe un sistem, se
poate folosi comanda ps -ef (pentru SVR4) sau ps aux (pentru BSD sau
Linux).

126
UNIX

Crearea proceselor se face în UNIX prin intermediul apelului de


sistem fork. Cele mai importante apeluri de sistem sunt: fork, wait, exec şi
exit. Prezentăm în continuare câteva caracteristici ale acestor apeluri de
sistem.
Apelul de sistem fork
Un proces este creat în UNIX cu ajutorul apelului de sistem fork.
Apelul fork crează un duplicat al procesului apelant. Noul proces se numeşte
copil iar procesul care l-a generat se numeşte părinte. Procesul copil
porneşte imediat după apelul fork şi ambele procese partajează la început
UCP (Unitatea Centrală de Procesare). Procesul copil menţine o copie
pentru: mediul procesului părinte, fişierele deschise, identificatorii
utilizatorului, valoarea umask, directorul curent de lucru şi semnale. În
momentul introducerii unei comenzi, shell-ul interpretează lexical linia de
comandă şi determină dacă primul cuvânt introdus este o comandă internă
sau o comandă externă regăsită într-un fişier pe hard disc. În primul caz,
shell-ul execută comanda internă, dar în cel de-al doilea caz shell-ul
apelează un apel fork pentru a face o copie a sa. Procesul copil va căuta
comanda în directoarele specificate în variabila PATH; în acest timp
procesul părinte se află în starea sleep.
Apelul de sistem wait
Procesul părinte este programat să intre în starea sleep (de aşteptare)
în timp ce procesul copil execută redirectarea, mecanismele pipe şi
procesarea în background. Apelul de sistem wait face ca procesul părinte
să-şi suspende execuţia până când unul dintre copiii săi îşi încheie
activitatea. Dacă procesul wait se desfăşoară normal, va returna PID-ul şi
exit-status-ul procesului copil care s-a încheiat.
Dacă procesul părinte nu este în stare de aşteptare iar copilul termină
activitatea, atunci procesul copil intră în starea zombie, rămânând în această
stare până când fie apelul părinte intră în starea wait, fie procesul părinte
se termină (pentru a înlătura procesele zombie, sistemul trebuie repornit).
Dacă părintele „moare” înaintea copilului (care devine orfan), procesul init
va prelua (adopta) un proces zombie orfan. Apelul de sistem wait asigură în
acest caz şi faptul că procesul se va termina în mod corespunzător.

Apelul de sistem exec


După introducerea unei noi comenzi la linia de comandă, shell-ul
generează în mod normal un apel fork, ce produce procesul copil. După cum
am spus mai înainte, procesul copil este responsabil cu execuţia comenzii
introduse, prin intermediul apelului de sistem exec. În momentul în care
programul executabil asociat comenzii este găsit, shell-ul cheamă apelul

127
Shell-uri UNIX

exec cu numele comenzii drept argument. Kernelul încarcă noul program în


memorie în locul shell-ului apelant, apoi procesul copil se suprapune peste
noul program. Noul program devine proces copil şi îşi începe execuţia. Deşi
noul proces are propriile variabile locale, toate variabilele de mediu,
fişierele deschise, semnalele, directorul curent de lucru sunt transmise
noului proces. În momentul în care procesul se termină, shell-ul părinte „se
trezeşte” (iese din starea wait).
Apelul de sistem exit
Orice program îşi poate încheia execuţia prin apelul de sistem exit.
În momentul în care un proces copil îşi încheie execuţia, el trimite un
semnal (sigchild) şi aşteaptă acceptul de terminare (exit) de la procesul
părinte. Orice program care se termină returnează, de asemenea, o valoare
corespunzătoare încheierii (cu succes sau nu) programului, denumită
exit-status. Exit-status-ul reprezintă un număr între 0 şi 255. În general, un
exit-status egal cu valoarea 0 (zero) indică faptul că programul s-a încheiat
cu succes şi o valoare diferită de 0 în caz contrar.
De exemplu, dacă comanda cp a fost introdusă la linia de comandă,
procesul shell părinte va iniţia prin fork un proces copil şi va intra în starea
sleep. Procesul copil va executa comanda cp în locul procesului părinte,
moştenind toate variabilele de mediu, fişierele deschise, informaţiile legate
de utilizator,etc. În momentul terminării execuţiei comenzii cp, se va genera
un exit iar procesul părinte va ieşi din starea de aşteptare, apărând
prompter-ul pe ecran. Fiecare shell are o variabilă (internă) specială prin
care putem determina valoarea exit-status-ului ultimei comenzi încheiate
(variabila este $? pentru shell-ul Bourne).

6.5.5 Mediul de lucru şi drepturi de acces

În momentul conectării la sistem (login), shell-ul îşi porneşte


execuţia, moştenind o serie de variabile de sistem, fluxuri de I/O
(Input/Output), precum şi caracteristicile procesului rezultat din execuţia
programului /bin/login. În continuare, dacă alt proces copil este iniţiat de
procesul părinte, acest proces copil va moşteni la rândul său caracteristicile
procesului părinte. Caracteristicile mediului constau în permisiunile
procesului (cine deţine procesul), directorul curent de lucru, „masca” de
creare a fişierului (file mask), o serie de variabile speciale, fişiere deschise,
semnale.
În momentul login-ului, shell-ul primeşte „o identitate”; are un
identificator al utilizatorului real (UID - User Identification), unul sau mai
mulţi identificatori de grup (GID - Group Identification), un identificator al
utilizatorului efectiv (EUID - Effective User Identification) şi un

128
UNIX

identificator al grupului efectiv (EGID - Effective Group Identification).


Iniţial, EUID şi EGID sunt identici cu UID şi, respectiv, GID.
Aceşti identificatori se găsesc în fişierul passwd, fiind utilizaţi de
către sistem pentru a identifica utilizatorii şi grupurile de utilizatori.
Identificatorii EUID şi EGID determină drepturile pe care le are un proces,
referitoare la operaţiile de citire, scriere sau execuţie a unui fişier. În cazul
în care EUID şi UID ale unui proces coincid, procesul are drepturile de
acces ale proprietarului asupra fişierului. Dacă EGID şi GID ale unui proces
coincid, acest proces deţine privilegiile grupului proprietar.
Identificatorul UID (ce se regăseşte în fişierul /etc/passwd, al treilea
câmp) este un număr pozitiv ce este în mod unic asociat cu numele de login
(numele utilizatorului). În momentul operaţiei de login, shell-ul primeşte
identificatorul UID şi toate procesele ce vor fi iniţiate de acesta vor moşteni
drepturile sale de acces. Orice proces care rulează cu un UID=0 aparţine
super-utilizatorului root şi are, astfel, drepturi de root. Identificatorul GID
realizează asocierea numelui de utilizator cu un nume de grup, regăsindu-se
în acelaşi fişier /etc/passwd pe coloana a 4-a. Identificatorii efectivi EUID şi
EGID pot fi modificaţi; prin modificarea lui EUID (sau EGID) către alt
utilizator, putem deveni proprietarii unui proces ce aparţine altui utilizator.
Programele ce modifică identificatorii EUID şi EGID sunt setuid şi setgid.
De aceea, programele setuid sunt deseori surse de breşe în securitatea
sistemului. Programul /bin/passwd este un exemplu de program setuid ce
oferă drepturi de root.

Comanda umask
În momentul creării unui nou fişier, acesta are o serie de drepturi de
acces implicite. Aceste drepturi de acces sunt determinate de programul ce a
creat fişierul, având în vedere că procesele copil moştenesc o aşa numită
„mască implicită” (default mask) de la procesele părinte. Utilizatorul poate
modifica această mască prin utilizarea comenzii umask. Comanda umask se
utilizează atunci când dorim să modificăm masca implicită. Iniţial, umask
este 000, ceea ce oferă unui director drepturile 777 (rwxrwxrwx) şi unui
fişier drepturile 666 (rw-rw-rw-). Pe majoritatea sistemelor, umask este setat
iniţial la valoarea 022 de către programul /bin/login sau de către fişierul de
configurare iniţială /etc/profile. Dar cum se calculează drepturile de acces în
funcţie de valoarea lui umask?
Pentru directoare, se scade valoarea lui umask din valoarea 777, iar
pentru fişiere se scade valoarea lui umask din valoarea 666. Astfel, pentru un
umask egal cu valoarea 022, un director va avea drepturile 755 (rwxr-xr-x),
iar un fişier va avea drepturile de acces 644 (rw-r--r--). Imediat după setarea

129
Shell-uri UNIX

valorii lui umask, toate fişierele şi directoarele nou create vor avea noile
drepturi de acces specificate, conform exemplului de mai înainte.
Comanda chmod
Pentru a modifica drepturile de acces la anumite fişiere şi/sau
directoare, se poate utiliza comanda chmod (change mode). Pentru fiecare
fişier de pe un sistem UNIX, există un unic proprietar al acestuia. Doar
proprietarul şi utilizatorul root au dreptul de a modifica drepturile de acces
la un anumit fişier sau director.
Cele opt posibilităţi de stabilire a drepturilor de acces la fişiere

Tabelul 6.2
Valoare octală Valoare zecimală Drepturi de acces
000 0 ---
001 1 --x
010 2 -w-
011 3 -wx
100 4 r--
101 5 r-x
110 6 rw-
111 7 rwx

Fiecare fişier UNIX are o serie de drepturi de acces (citire, scriere,


execuţie) pentru proprietar, grupul din care face parte şi restul utilizatorilor.
Aceste drepturi de acces sunt stocate în câmpul mode al inode-ului
fişierului. Comanda chmod este deci folosită pentru a modifica drepturile de
acces la un fişier sau director. Utilizatorul trebuie să fie proprietarul
fişierului pentru a putea modifica aceste drepturi (identificatorul EUID al
apelantului trebuie să fie acelaşi cu UID, sau root). În tabelul 6.2 avem
ilustrate cele opt posibilităţi de drepturi de acces la fişiere. De asemenea, în
figura 6.3 sunt prezentate câteva exemple de utilizare a comenzii chmod. În
primul caz, argumentul comenzii chmod este 754, aceasta însemnând rwx
pentru proprietar, r-x pentru grup şi r-- pentru ceilalţi utilizatori. În cazul al
doilea, este adăugată (opţiunea +) permisiunea de scriere (w) pentru grup.
În a treia comandă, se iau (opţiunea -) drepturile de citire (r) şi execuţie (x)
pentru grup şi ceilalţi utilizatori, iar în ultimul exemplu, toţi (a-all)
utilizatorii primesc (doar) dreptul de citire. Operatorul egal (=) face ca toate
drepturile anterioare să fie resetate la noua valoare.

130
UNIX

Figura 6.3 Exemple de utilizare a comenzii chmod

Comanda chown
Comanda chown (change owner) modifică proprietarul şi grupul
pentru fişiere şi directoare. Ca şi în cazul comenzii chmod, doar proprietarul
şi root au dreptul de a face acest lucru (pe anumite versiuni de UNIX,
precum BSD, doar utilizatorul root poate face acest lucru). În figura 6.4
avem un exemplu de utilizare a acestei comenzi (se modifică proprietarul
fişierului test din root în daemon).

Figura 6.4 Exemplu de utilizare a comenzii chown


Directorul de lucru
În momentul procesului de login, fiecare utilizator este poziţionat
într-un director anume, care se numeşte directorul home. Directorul home
este moştenit de toate procesele iniţiate din cadrul acestui shell. Orice proces
copil poate modifica propriul director de lucru, dar aceste modificări nu vor
afecta procesul shell părinte. Comanda cd (change directory) este o
comandă internă a sistemului UNIX. Fiecare shell deţine propria copie a
comenzii cd. O comandă internă este executată de shell direct ca parte a
propriului cod; shell-ul nu face apeluri fork şi exec atunci când execută
comenzi interne. Dacă un alt shell-script este iniţiat prin fork de către
procesul părinte, comanda cd va fi executată în shell-ul copil şi directorul va
fi modificat aici. Atunci când procesul copil se termină, procesul părinte va
fi în acelaşi director ca şi înainte de a fi pornit procesul copil. În figura 6.5
este ilustrat acest fapt.

131
Shell-uri UNIX

Figura 6.5 Directorul de lucru


Semnale
În momentul în care un semnal trimite un mesaj unui proces, acesta
din urmă se termină. Putem trimite semnale unui proces prin apăsarea
tastelor BREAK, DELETE, QUIT şi STOP, iar toate procesele acelui
terminal vor fi afectate de semnalul trimis. Putem opri un proces aflat în
execuţie prin comanda kill. Shell-ul permite manipularea semnalelor trimise
programelor, fie prin ignorarea lor, fie prin specificarea unei acţiuni în
momentul apariţiei unui anumit semnal. Mai multe detalii legate de
semnalele UNIX sunt prezentate în secţiunea 7.6.7.

6.6 Scrierea unui shell-script


În momentul în care utilizăm facilităţile de limbaj de programare ale
shell-ului, vom construi programe (shell-script-uri) care cuprind comenzi
UNIX şi constructori de control shell. Cum realizăm acest lucru? Utilizând
un editor de texte, vom scrie comenzile şi construcţiile shell şi vom salva
fişierul cu un nume oarecare (script.sh, spre exemplu). Liniile din cadrul
shell-script-ului vor fi interpretate una câte una de către shell (avem de-a
face cu programe interpretate, nu compilate).
De regulă, prima linie dintr-un fişier shell-script indică tipul de shell
utilizat. Spre exemplu, dacă folosim shell-ul Bourne, prima linie va arăta
astfel:
#!/bin/sh

iar dacă utilizăm shell-ul bash, prima linie va arăta:


#!/bin/bash

După ce salvăm fişierul, trebuie să îi dăm drepturi de execuţie (vom


folosi comanda chmod) şi în acest moment suntem gata să îl rulăm. Putem
lansa în execuţie programul intitulat script.sh astfel (./ semnifică faptul că
acesta se află în directorul de lucru curent):
$ ./script.sh

132
1. Bourne Shell

7 BOURNE SHELL

7.1 Tipuri de operatori şi comenzi

Ca în toate limbajele de programare, operatorii permit


programatorilor să utilizeze diverse operaţii (aritmetice, logice, string etc.)
asupra variabilelor. Bourne shell suportă trei tipuri de operatori:
ƒ aritmetici
ƒ de test
ƒ logici
Operatorii aritmetici sunt folosiţi doar pentru operaţiile cu numere
întregi.
Operatorii de test sunt folosiţi pentru operaţii cu fişiere, cu variabile
string şi cu întregi.

7.1.1 Comanda test

Această comandă are forma: test <conditie> sau [ <conditie> ],


atunci când este folosită ca parte a unei comenzi if.
Observaţie:
<conditie> are forma: [<operand1>][<operator>]<operand2>
Exemple:

$ test $sir1 != $sir2

(în exemplele folosite semnul $ de la începutul rândului reprezintă


prompter-ul shell-ului).
Condiţia va întoarce o valoare zero (adevărat) dacă variabila sir1
este diferită ca valoare de variabila sir2 şi o valoare diferită de zero (fals) în
caz contrar. Această valoare poate fi verificată prin intermediul lui exit

133
UNIX

status (parametrul special shell $?) care întoarce valoarea de adevăr a


ultimei operaţii efectuate.
Fie secvenţa de comenzi următoare:
$ var1=15
$ var2=20
$ test $var1=$var2
$ echo $?

Se va afişa valoarea 1, care semnifică faptul că testarea s-a încheiat


cu valoarea "false" (variabila var1 are o valoare diferită de variabila var2).

7.1.2 Operatori pentru fişiere

Aceştia sunt operatori unari (cu un singur argument) şi de cele mai


multe ori argumentul este numele unui fişier.
Dintre aceşti operatori amintim:
ƒ -d <fişier> : este director?
ƒ -f <fişier> : este fişier obişnuit?
ƒ -g <fişier> : are setat identificatorul GID?
ƒ -r <fişier> : poate fi citit?
ƒ -s <fişier> : este de lungime diferită de zero?
ƒ -w <fişier> : poate fi modificat?
ƒ -x <fişier> : este fişier executabil?
Exemplu.
Fie comanda:

$ ls -las

cu efectul următor:
total 5
4 drwxrwxrwx 1 root root 2048 Feb15 18:00 .
4 drwxrwxrwx 1 root root 2048 Feb15 18:10 ..
2 -rwxrwxrwx 1 razvan cib 1022 Dec15 17:45 .profile
1 -rwxrwxrwx 1 razvan cib 102 Feb16 17:45 stud.dat
2 -rwxrwxrwx 1 razvan cib 1102 Dec10 17:45 examen.dat

134
Bourne shell

Fie comanda:

$ test -f stud.dat; echo $?

Se va afişa 0, având în vedere că stud.dat este într-adevăr fişier


obişnuit.

Exerciţiu:
Ce se va afişa pentru următoarele comenzi?

$ test -d examen.dat; echo $?


$ test -x examen.dat; echo $?
$ test -s examen.dat; echo $?
$ [ -r examen.dat ] ; echo $?
$ [ -w stud.dat ] ; echo $?

7.1.3 Operatori pentru şiruri de caractere

Operatorii folosiţi pentru operaţii cu şiruri de caractere sunt:


ƒ <sir1> : este sirul <sir1> nenul?
ƒ -n <sir1> : are sirul <sir1> lungimea diferita de zero?
ƒ -z <sir1> : are sirul <sir1> lungimea zero?
ƒ <sir1>=<sir2> : este sirul <sir1> identic cu <sir2>?
ƒ <sir1>!=<sir2> : este sirul <sir1> diferit de <sir2>?
Observaţie:
În general, este bine ca variabilele shell folosite în testare să fie
încadrate de ghilimele: "nume_variabila".

Exemple.
Atribuire cu valoare null:

$ var=

135
UNIX

Comanda:

$ test $var=hello ; echo$?

nu este corectă deoarece $var trebuie să apară între ghilimele; în


concluzie, corect este:

$ test “$var”=hello; echo $?

(Explicaţie: comanda test aşteaptă 3 parametri: $var, =, hello.


Conversia efectivă a lui $var la valoarea sa se face înainte de interpretarea
întregii comenzi. Deoarece valoarea lui $var este null, va rezulta
interpretarea unei comenzi de genul test =hello, de unde rezultă eroarea).
Ghilimelele au rolul de separator pentru caracterul null.

Exerciţiu.
Fie atribuirile:
$ sir1=dan
$ sir2=maria
$ sir3=dan
$ sir4=

1. Care dintre comenzile următoare vor produce mesaje de eroare la


execuţie?
a. [ $sir1 ] ; echo $?
b. [ -n $sir3 ] ; echo $?
c. [ $sir1=$sir4 ] ; echo $?
d. [ "$sir4"="$sir3" ] ; echo $?
e. [ -z $sir4 ] ; echo $?

2. Care dintre comenzile următoare vor avea rezultat un exit status


egal cu zero?

136
Bourne shell

a. [ "$sir1"!="$sir2" ] ; echo $?
b. [ -z "$sir3" ] ; echo $?
c. [ -n "$sir4" ] ; echo $?
d. [ "$sir1"="$sir3" ] ; echo $?
e. [ "sir4" ] ; echo $?

7.1.4 Operatori pentru tipul integer

Sintaxa utilizării operatorilor pentru operaţii cu numere întregi este:

[ int1 operator int2 ]

iar operatorii utilizaţi sunt:


ƒ -eq : se testează egalitatea lui int1 cu int2
ƒ -ge : se testează dacă int1 este mai mare sau egal decât int2
ƒ -gt : se testează dacă int1 este mai mare strict decât int2
ƒ -le : se testează dacă int1 este mai mic sau egal decât int2
ƒ -lt : se testează dacă int1 este mai mic decât int2
ƒ -ne : se testează dacă int1 este diferit de int2

Exerciţii.
1. Fie atribuirile:

int1=5
int2=10
int3=55
int4=5

Ce vor afişa comenzile:

a. [ "$int1" -gt "int2" ] ; echo $?


b. [ "$int2" -lt "$int3" ] ; echo $?
c. [ "$int4" -le "$int1" ] ; echo $?
d. [ "$int3" -eq "$int4" ] ; echo $?
e. [ "$int4" -ne "$int1" ] ; echo $?

137
UNIX

2. Fie atribuirile:

V1=007
v2=7

Ce vor afişa fiecare dintre comenzile:

a. [ "$v1" = "$v2" ] ; echo $?


b. [ "$v2" -eq "$v2" ] ; echo $?

7.1.5 Operatori pentru tipul boolean

Operatorii utilizaţi sunt:

1. ! <expresie> : expresie falsă?


2. <expresie1> -a <expresie2> ambele adevărate?
3. <expresie1> -o <expresie2> una dintre ele adevărată?

Exemplul 1.
Fie atribuirile:

v1=5
v2=10

Ce va afişa comanda:

[ !"$v1" -eq "$v2" ] ; echo $? (0)

Exemplul 2.
Fie comanda:

[ -f “fisier” -a -x "fisier" ]

138
Bourne shell

Rezultatul va fi zero dacă fişier este atât fişier obişnuit cât şi


executabil.

Exemplul 3.
Fie comanda:

[ "$var" -qt 1 -a "$var" -lt 90 ]

Rezultatul este zero dacă variabila var are o valoare cuprinsă între 1
şi 90 (strict).
Observaţie. Operatorul -a are o prioritate mai mică decât operatorii
de comparaţie pentru întregi.

Exemplul 4.
Fie comanda:

[ -r "stud" -o -d "stud" ]

În acest caz, rezultatul este zero dacă stud poate fi citit sau dacă este
director.

Exemplul 5.
Fie comanda:

[ "$luna" -gt 12 -o "$ziua" -gt 31]

Rezultatul este zero dacă luna este mai mare decât 12 sau dacă ziua
are o valoare mai mare decât 31.

7.1.6 Operatori pentru tipul logic

Operatorii utilizaţi sunt:

1. &&
2. ||

139
UNIX

Aceşti operatori permit execuţia unei comenzi în cazul în care


comanda precedentă se încheie cu succes sau nu. Astfel, dacă avem
următoarea construcţie: comanda1 && comanda2, atunci comanda2 este
executată dacă exit status-ul comenzii comanda1 este zero.
În mod asemănător, pentru construcţia comanda1 || comanda2,
comanda2 este executată doar dacă exit status-ul comenzii comanda1 este
diferit de zero.

Exemplul 1.
Fie comanda:

[ -x “fisier_prog” ] && fisier_prog

Dacă fişierul fsşier_prog este executabil, atunci se lansează în


execuţie.

Exemplul 2.
Fie comanda:

[ "$luna" -le 12 -a "$ziua" -lt 32 ] || \


echo “Data invalida $an $luna $ziua”

Dacă luna sau ziua au valori invalide, atunci se execută comanda


echo.

Observaţii.
1. Caracterul "\" (backslash) de la sfârşitul liniei anulează
semnificaţia specială a caracterului newline şi îl consideră caracter
whitespace. Cu alte cuvinte, comanda se continuă pe linia următoare.
2. Parantezele rotunde (,) au semnificaţie specială şi nu pot fi folosite
în shell-script-uri în scopul grupării diverselor comparări. Pentru a ignora
semnificaţia specială a parantezelor într-o comandă se foloseşte tot
caracterul de evitare "\". Comanda anterioară poate fi rescrisă astfel:

[ \("$luna" -le 12 \) -a \("$ziua" -lt 32 ] \)|| \


echo “Data invalida $an $luna $ziua”

140
Bourne shell

7.1.7 Operatori aritmetici

Operatorii aritmetici sunt: +, -, *, /, % (împărţire modulo).


Deoarece shell-ul nu are alt concept de dată decât character string
(şir de caractere), pentru a se putea face calcule aritmetice se va folosi
comanda expr, care informează shell-ul că şirul de caractere ce urmează
după expr trebuie evaluat ca expresie matematică.

Exemplul 1.
Fie atribuirile:

x=9
x=$x+6

În acest caz, comanda echo "$x" va afişa 9+6 şi nu rezultatul


adunării.

Exemplul 2.
Comanda expr are de-a face numai cu numere întregi, astfel
rezultatul expr 15 / 6 va fi 2.

Observaţii.
1. Operanzii şi operatorii dintr-o expresie aritmetică trebuie separaţi
de cel puţin un spaţiu. Astfel, dacă scriem comanda de mai sus fără spaţii
între 15 şi 6 : expr 15/6, rezultatul va fi 15/6.
2. Deoarece operatorul "*" are o semnificaţie specială pentru shell,
trebuie ca atunci când vrem să facem o operaţie de înmulţire, să folosim
caracterul de evitare (\).
Deci, dacă x=3, y=4, z=5, atunci expr $x * $y este o comandă
eronată, pe când expr $x \* $y \* $z va avea ca rezultat 60.
3. Cea mai folosită operaţie este incrementarea:

var=`expr $var + 1`

141
UNIX

7.2 Gramatica Shell

7.2.1 Comenzi simple

O comandă este o secvenţă de atribuiri (opţional) urmate de cuvinte


separate de spaţii şi redirectări, terminate cu un operator de control (||, &,
&&, ; , ;; , ( , ) , | , <newline>). Primul cuvânt reprezintă comanda ce va fi
executată iar celelalte sunt interpretate ca argumente ale comenzii. Valoarea
întoarsă de o comandă este exit status, sau valoarea numerică 128+n dacă
respectiva comandă se încheie cu semnalul n.

7.2.2 Conducte (pipelines)

O secvenţă pipeline este aceea în care una sau mai multe comenzi
sunt separate de simbolul pipe ( | ) - bară verticală. Formatul general al unei
secvenţe pipeline este:

[!] comanda1 [| comanda2 ...]

Ieşirea standard a comenzii 1 este conectată la intrarea standard a


comenzii 2. Dacă apare caracterul de negare (!), exit status-ul pipeline-ului
va fi valoarea negată a exit status-ului ultimei comenzi. Shell-ul aşteaptă
terminarea tuturor comenzilor din pipeline înainte de a întoarce un rezultat.
Fiecare comandă dintr-o secvenţă pipeline este executată ca un proces
separat (într-un sub-shell).

7.2.3 Redirectare

Redirectarea fişierelor standard de intrare şi de ieşire către alte


dispozitive periferice sau fişiere se face folosind operatorii > , >> , < , << .
Operatorii > şi >> se folosesc pentru redirectarea fişierului standard de ieşire
(output-ului).

Exemple.
ƒ ls -al > f1 - această comandă redirectează afişarea comenzii ls în
fişierul f1 în loc ca ieşirea să fie afişată pe ecran.
ƒ ls -al >> f1 - această comanda redirectează afişarea comenzii ls
în fişierul f1 prin adăugare la sfârşitul lui f1 (fişierul f1 nu este
suprascris).

142
Bourne shell

Operatorul < se foloseşte pentru redirectarea fişierului standard de


intrare (input-ului).

Exemplu.

$ mail serban < mesaj

Această comandă trimite un mesaj (preluat din fişierul mesaj) prin


email utilizatorului serban.

7.2.4 Liste

O listă este o secvenţă de una sau mai multe pipelines separate de


unul sau mai mulţi operatori ; , & , && sau || şi terminată cu ; , & sau
<newline>.
Dacă o comandă se termină cu operatorul de control &, shell-ul
execută comanda respectivă în background într-un subshell. Shell-ul nu
aşteaptă terminarea comenzii şi întoarce valoarea zero.
Comenzile separate de caracterul “;” sunt executate secvenţial,
shell-ul aşteaptă terminarea fiecăreia dintre comenzi, iar valoarea întoarsă
este exit status-ul ultimei comenzi executate.
Operatorul && se foloseşte sub forma: comanda1 && comanda2 şi
în acest caz comanda2 este executată dacă şi numai dacă comanda1
întoarce un exit status zero.
Operatorul || se foloseşte astfel: comanda1 || comanda2 , comanda2
executându-se dacă şi numai dacă comanda1 returnează un exit status
diferit de zero. Exit status-ul returnat este acela al ultimei comenzi
executate.

7.2.5 Comenzi compuse

Există două modalităţi de grupare a mai multor comenzi: prin


folosirea parantezelor rotunde ( ) şi prin folosirea acoladelor { }. Astfel,
construcţia următoare:
(lista_de_comenzi) face ca modificările aduse mediului de comenzile
respective să nu aibă efect după terminarea comenzii (se rulează într-un
subshell).
Construcţia {lista_de_comenzi;} face ca modificările să aibă efect
asupra mediului existent deoarece lista de comenzi este executată în mediul
shell existent.

143
UNIX

7.2.6 Caracterul escape

Caracterul escape (\) are o semnificaţie specială în shell, fiind folosit,


de regulă, pentru a se ignora semnificaţia specială a unor caractere. Spre
exemplu, folosit la sfârşitul unui rând şi urmat de caracterul <newline>, \
este considerat ca şi continuator de linie, astfel încât comanda se poate
continua pe linia următoare. Se poate folosi această facilitate atunci când
avem de-a face cu comenzi foarte lungi pe care le putem scrie mai
convenabil pe două sau chiar mai multe linii.
Caracterul backslash îşi păstrează semnificaţia specială dacă este
urmat de $ , ` , " , \ sau <newline>.

7.2.7 Comentarii într-un shell-script

Comentariile într-un shell-script se introduc folosindu-se caracterul


#, care face să se ignore caracterele existente după semnul # şi până la
sfârşitul liniei respective (excepţie face construcţia #!nume_shell care apare
pe prima linie a shell-script-ului şi specifică tipul de shell utilizat).

7.2.8 Variabile

O variabilă este o entitate ce memorează valori într-un mod


asemănător unei variabile într-un limbaj de programare convenţional. O
variabilă este setată atunci când i se atribuie o valoare (variabila=valoare),
putând fi dezactivată folosind comanda unset.
Variabilele shell pot fi modificate în mod dinamic de către
interpretor sau atribuite la intrarea în sesiune.
Dintre variabilele modificate dinamic enumerăm:
ƒ $# - reprezintă numărul parametrilor poziţionali ai unui program
shell;
ƒ $? - reprezintă exit status-ul (codul de revenire) celei mai recente
comenzi executate;
ƒ $- - reprezintă opţiunea curentă cu care a fost lansat shell-ul;
ƒ $$ - reprezintă identificatorul de proces al shell-ului;
ƒ $! - reprezintă identificatorul de proces al celei mai recente
comenzi lansate în background;
ƒ $0 - reprezintă numele shell-ului sau al shell-script-ului;
ƒ $1..$9 - reprezintă argumentele (parametrii) ultimei comenzi
lansate în execuţie la linia de comandă;
ƒ $_ - reprezintă ultimul argument al comenzii anterioare.

144
Bourne shell

Dintre variabilele atribuite la intrarea în sesiune enumerăm:


ƒ $HOME - reprezintă directorul atribuit utilizatorului (directorul
implicit) la intrarea în sesiune;
ƒ $PATH - reprezintă lista directorilor ce sunt parcurşi de shell la
căutarea unui fişier executabil corespunzător comenzii introduse;
ƒ $PS1 - reprezintă prompter-ul asociat interpretorului;
ƒ $PS2 - reprezintă al doilea prompter (pentru continuarea liniei de
comandă, cel implicit este >);
ƒ $MAIL - reprezintă numele directorului implicit pentru poşta
electronică;
ƒ $LOGNAME - reprezintă numele de login al utilizatorului;
ƒ $SHELL - reprezintă numele interpretorului de comenzi implicit
atribuit la intrarea în sesiune (acesta se poate schimba folosind
comanda chsh);
ƒ $TERM - reprezintă tipul de terminal folosit de editorul vi şi de
alte editoare orientate pe ecran.

7.3 Instrucţiuni de selecţie

7.3.1 Instrucţiunea if

Sintaxa acestei instrucţiuni este:

if <com_test1>
then
<secventa_comenzi1>
else
<secventa_comenzi2>
fi

unde else este opţional.


În astfel de situaţii este folosită scrierea testărilor folosind notaţia cu
paranteze drepte în loc de comanda test.

145
UNIX

Exemplul 1.

unitati=0
if [ “$contor” -lt 10]
then
unitati=`expr $unitati + 1`
else
unitati=0
zeci=1
fi

Instrucţiunile if pot fi încuibate, după modelul:

if <com_test1>
then
if <com_test2>
then
<secventa_comenzi1>
fi
else
if <com_test3>
then
<secventa_comenzi2>
fi
fi

O alternativă a construcţiei else...if este dată de elif:

if <com_test1>
then
<secventa_comenzi1>
elif <com_test2>
then
<secventa_comenzi2>
else
<secventa_comenzi3>
fi

146
Bourne shell

Exemplul 2.
Fie un shell-script denumit verif_fisier care ia drept argument un
nume de fişier şi verifică dacă este director sau fişier obişnuit:

if [ -f "$1" ]
then
echo "$1 este fişier obisnuit!"
elif [ -d $1 ]
then
echo "$1 este director!"
fi

7.3.2 Comanda null

Comanda null este reprezentată de caracterul special : (în engleză


colon) şi este o comandă „care nu face nimic” şi returnează un exit-status
egal cu zero. Această comandă se poate utiliza în cadrul unei comenzi if
când nu avem nici un mesaj de afişat sau altă comandă de efectuat (conform
sintaxei comenzii if trebuie însă introdusă o comandă după cuvântul cheie
then pentru a nu produce o eroare).
Fie exemplul următor:

#!/bin/sh
nume=george
if grep “$nume” database > /dev/null 2>&1
then
:
else
echo “$nume nu a fost gasit in baza de date!”
exit 1
fi

Conform acestui shell-script se caută în fişierul database şirul de


caractere george folosind comanda grep. Dacă acest şir de caractere este
găsit, se execută comanda null care va returna un exit-status de valoare zero
(programul se termină cu succes); dacă nu, se va afişa mesajul
corespunzător faptului că george nu a fost găsit în baza de date şi programul
se va încheia cu un exit-status egal cu 1.

147
UNIX

7.3.3 Instrucţiunea case

Sintaxa instrucţiunii case este:

case <valoare> in
sablon_1) <comanda11>
<comanda12>
...
<comanda1n>;;
sablon_2) <comanda21>
<comanda22>
...
<comanda2n>;;
...
sablon_m) <comandam1>
<comandam2>
...
<comandamn>;;
esac

Observaţie. Putem utiliza metacaracterul * pentru a specifica orice


şablon, dacă nici unul nu a fost adevărat.

Exemplul 1.
Presupunem că avem un program care cere o opţiune pentru
următorul meniu:

Alegeti opţiunea dintre variantele:


1...Afisarea unui fisier
2...Stergerea unui fisier
3...Iesire din program

Codul de program pentru citirea opţiunii şi verificarea acesteia este:

Observaţie:

148
Bourne shell

Dacă utilizatorul trebuie să introducă o literă în locul unei cifre şi


dorim să nu conteze dacă litera introdusă este majusculă sau nu, putem să
înlocuim 1) cu a|A) în cazul în care "A" este opţiunea pentru afişarea unui
fişier, 2) cu s|S) în cazul în care "S" este opţiunea pentru ştergerea unui
fişier şi 3) cu i|I) în cazul în care "I" este opţiunea pentru ieşirea din
program.

Exemplul 2.
Considerăm programul următor:
#!/bin/sh
# Nume shell-script: culori
echo "Ce culoare va place? "
read culoare
case "$culoare" in
[Aa]l??????)
echo $culoare este culoarea cerului!
;;
[Vv]erde)
echo Padurea este $culoare !
;;
galben | portocaliu) # Bara verticala semnifica "sau"
echo $culoare este o culoare calda!;;
*)
echo Nu stiu nimic despre culoarea $culoare;;
esac
echo "Sfarsit case"

Explicaţii:
Se citeşte la început un şir de caractere care este atribuit variabilei
culoare. Comanda case evaluează expresia $culoare. În cazul în care
culoarea introdusă începe cu A sau a, continuă cu litera l şi urmează alte
6 caractere (pentru a se forma Albastru sau albastru), se afişează mesajul
corespunzător şi instrucţiunea case se încheie.
Dacă nu este îndeplinită prima condiţie, se continuă cu verificarea
celorlalte două condiţii (pentru culorile verde, apoi pentru galben şi
portocaliu) şi dacă nici acestea nu sunt îndeplinite se va afişa mesajul care
corespunde opţiunii *, ce reprezintă toate celelalte cazuri (un fel de else în
cazul instrucţiunii case, atunci când toate celelalte condiţii anterioare nu au
fost îndeplinite). În final, instrucţiunea case se termină cu cuvântul cheie
esac şi este afişat mesajul de ieşire din instrucţiunea case.

149
UNIX

7.4 Instrucţiuni iterative

7.4.1 Instrucţiunea for

Sintaxa instrucţiunii for este:

for <variabila> in <valoare_1> <valoare_2> <valoare_n>


do
<comenzi>
done

Exemplul 1.
Secvenţa următoare de program copiază fişierele cu numele fis1, fis2
şi fis3 în directorul copie din directorul curent:

for f in fis1 fis2 fis3


do
cp $f copie
done

Comanda for poate fi folosită pentru ciclarea printre elementele


conţinute de variabila specială $*. Secvenţa următoare afişează argumentele
cu care este apelat shell-script-ul (presupunem că îl denumim afisare_arg).

for argum in $*
do
echo "$argum"
done

Exemplul 2.
În acest exemplu presupunem că avem de trimis acelaşi mesaj prin
e-mail mai multor persoane. Adresele de e-mail ale persoanelor vor fi
introduse anterior într-un fişier text simplu, fiecare adresă de email pe câte
o linie. Dacă denumim fişierul cu adresele de e-mail adrese, acesta va arăta
astfel:

150
Bourne shell

stud
anca@yahoo.com
cristi@hotmail.com
george
paul
serban@k.ro

Observaţie. Avem de-a face în exemplul de mai sus cu trei adrese


complete de email şi cu trei adrese locale corespunzătoare utilizatorilor
locali stud, george şi paul.
Mesajul pe care îl trimitem se află în fişierul mesaj. Cu aceste
explicaţii, shell-script-ul este:

# Numele script-ului: trimite_mesaj


for persoana in `cat adrese`
do
mail $persoana < mesaj
echo A fost trimis mesajul lui $persoana.
done
echo "Mesajul a fost transmis."

7.4.2 Instrucţiunea while

Sintaxa instrucţiunii while este:

while <comanda_adev>
do
<comenzi>
done

Exemplul 1.
Secvenţa următoare de program citeşte o opţiune şi execută
comenzile specificate atât timp cât variabila final are valoarea "n".

151
UNIX

final=n
while [ "$final" = n ]
do
read opţiune
case "$opţiune" in
1) echo "Introduceti numele fişierului ce va fi\
afisat:"
read nf
cat "$nf";;
2) echo "Introduceti numele fişierului ce va fi\
sters:"
read nf
rm "$nf";;
3) fin=y
echo "Iesire din program..."
sleep 5;;
*) echo "Opţiune invalida!";;
esac
done

Exemplul 2.
Programul următor afişează pe rând argumentele cu care a fost
apelat. Folosind comanda shift putem face să afişăm întâi toate argumentele
apelului, apoi mai puţin cu unul, ş.a.m.d., până la ultimul argument.

while [ $# -gt 0 ]
do
echo $*
shift
done

Presupunând că programul se numeşte afisarg, apelul:

$ afisarg 1 2 3 4 5

va afişa:
12345
2345
345
45
5

152
Bourne shell

7.4.3 Instrucţiunea until

Sintaxa instrucţiunii until este:


until <comanda_adev>
do
<comenzi>
done

De regulă, instrucţiunea until se foloseşte atunci când trebuie


executată o secvenţă de instrucţiuni până în momentul în care o comandă se
termină cu valoarea de adevăr zero (true).
Exemplul 1.
Fie secvenţa următoare de program care verifică dacă un utilizator al
cărui nume este specificat drept argument în momentul apelului
shell-script-ului s-a conectat la sistem. În acest moment se afişează mesajul:
"Utilizatorul <nume_utilizator> s-a conectat!".

nume=$1
until who | grep “^$nume” > /dev/null
do
sleep 30
done
echo “Utilizatorul $1 s-a conectat!”

Comanda grep caută un şablon specificat (în cazul nostru numele


utilizatorului) într-un fişier. Metacaracterul "^" specifică faptul că şablonul
se potriveşte cu ieşirea comenzii who doar dacă este găsit la începutul liniei
(ştiind faptul că who afişează la începutul fiecărei linii numele utilizatorilor
conectaţi la sistem în momentul respectiv). Deoarece ieşirea comenzii grep
nu este folosită în nici un fel, ea este redirectată spre /dev/null.
Instrucţiunea sleep determină oprirea temporară a execuţiei
programului pentru un interval de 30 de secunde; cu alte cuvinte, verificarea
conectării utilizatorului se face la intervale de 30 de secunde. Dacă
shell-script-ul este denumit lookout, atunci el poate fi apelat în background
folosindu-se sintaxa:

$ lookout <nume_utilizator>&

iar mesajul de conectare va apărea în momentul în care utilizatorul


se conectează la sistem şi este "descoperit" de comanda lookout.

153
UNIX

Exemplul 2.
Următorul program va afişa câte un mesaj pentru toate orele zilei
între 8 şi 24:

ora=8
until [ $ora –gt 24 ]
do
case "$ora" in
[8-9] |1[0-1]) echo "Buna dimineata!"
;;
1[2-3]) echo "Ora pranzului!"
;;
1[4-6]) echo "Siesta!"
;;
*) echo "Buna seara!"
;;
esac
ora=`expr $ora + 1`
done

Execuţia programului va afişa pe ecran:

Buna dimineata!
Buna dimineata!
Buna dimineata!
Buna dimineata!
Ora pranzului!
Ora pranzului!
Siesta!
Siesta!
Siesta!
Buna seara!
Buna seara!
Buna seara!
Buna seara!
Buna seara!
Buna seara!
Buna seara!
Buna seara!

154
Bourne shell

7.4.4 Instrucţiunile break şi continue

Instrucţiunile break şi continue sunt instrucţiuni de salt, fiind folosite


în mod asemănător cu instrucţiunile omonime din limbajul C. Astfel,
instrucţiunea break determină ieşirea din cel mai interior ciclu ce o conţine
şi continuând cu execuţia primei comenzi după ciclul respectiv, iar
instrucţiunea continue determină saltul la începutul ciclului ce o conţine.
Exemplu
Secvenţa următoare de program citeşte valoarea unui an care trebuie
să fie cuprinsă între 1900 şi 2000 iar dacă nu se introduce nici o valoare se
reia introducerea anului.

valid=n
until [ "$valid" = y ]
do
echo "Introduceti anul (în intervalul 1900-2000) şi\
tastati <ENTER>"
read an
if [ "$an" = "" ]
then
continue
fi
if [ "$an" -lt 1900 -o "$an" -gt 2000 ]
then
echo "\n Anul trebuie sa fie în intervalul 1900-\
2000"
else
valid=y
fi
done

Ce se va întâmpla în cazul în care în exemplul anterior continue este


înlocuit de break?

7.5 Funcţii în Shell

Ca şi în limbajul C, avem posibilitatea şi în Bourne Shell să folosim


funcţii definite de utilizator pentru a conferi modularitate programelor. De
asemenea, funcţiile se apelează mai rapid decât ar fi apelate alte
shell-script-uri. La apelul unui alt shell-script, shell-ul trebuie să caute pe
hard disc programul şi să-l deschidă înainte de a fi citit, situaţie în care se
creează un nou proces; acest lucru nu se întâmplă în cazul apelului unei
funcţii.

155
UNIX

O funcţie definită într-un shell-script există doar în cadrul procesului


respectiv şi nu poate fi exportată.
Formatul general al declarării unei funcţii este:

nume()
{
<secventa_de_comenzi>
}

Parantezele rotunde ce urmează după numele funcţiei specifică


interpretorului de comenzi că este vorba despre o funcţie.

Observaţie:
Spre deosebire de limbajul C, parantezele ce urmează după numele
funcţiei nu au niciodată conţinut. Apelul funcţiei se face prin numele ei, ca o
comandă obişnuită; de aceea, numele funcţiilor nu trebuie să coincidă cu
numele comenzilor UNIX sau ale comenzilor Shell. O funcţie poate accesa
variabilele setate pentru shell-ul curent (atât cele stabilite la începutul
procesului de login cât şi cele ce se modifică pe parcurs). De regulă,
funcţiile se scriu la începutul shell-script-ului; în caz contrar, codul funcţiei
trebuie să preceadă apelul său.

Exemplu.
Fie funcţia:

go()
{
cd $1
PS1="`pwd`>"
}
go $1

Dacă numele shell-script-ului este gofunc, atunci el poate fi apelat în


modul următor:

$ gofunc /home/serban

iar rezultatul apelului va fi schimbarea directorului curent în


/home/serban şi schimbarea primului prompter în "/home/serban>".

156
Bourne shell

7.6 Mediul Shell

7.6.1 Apelurile fork şi exec

În UNIX, apelul de sistem fork determină producerea unui nou


proces. Apelul exec face ca un nou program să se suprapună peste noul
proces. După fiecare apel fork ce generează un nou proces, vechiul proces se
execută în continuare având conţinutul intact. Noul proces este identic cu
părintele sau până când exec se suprapune cu imaginea noului program.
Acest eveniment apare, de regulă, la execuţia unei comenzi.
Apelul de sistem wait suspendă execuţia shell-ului până când noul
proces este terminat. Atunci când apelul de sistem exec se autoapelează la
prompter-ul shell, conţinutul procesului vechi se pierde. Procesul original
este suprapus cu imaginea noului program. Spre exemplu, se poate
considera comanda:

$ exec ls -l

În acest caz, comanda anterioară este suprapusă peste procesul shell;


în momentul execuţiei sale, shell-ul se termină şi de aceea utilizatorul este
confruntat cu prompter-ul de login.
Un proces este un program în execuţie, fiecare proces având o arie
de memorie unde este stocată informaţia despre acesta. Un proces aflat în
execuţie este descris de o tabelă de procese. Tabela de procese conţine
informaţii precum:
ƒ identificatorul procesului (process id)
ƒ adrese de memorie
ƒ descriptori de fişiere.
Aceste informaţii sunt folosite de către kernel pentru controlul
execuţiei. Procesul în sine conţine codul ce va fi executat, având, de
asemenea, asociat o porţiune de date în memorie ce conţine informaţii
referitoare la mediul sistemului (variabilele de mediu).

7.6.2 Modalităţi de grupare a comenzilor shell

Există o serie de modalităţi de grupare a comenzilor shell:


ƒ grupare secvenţială: pwd;ls -l
ƒ grupare în paranteze: (pwd;ls -l)
ƒ grupare în background: sort fişier&
ƒ grupare în conductă (pipe): ls -l | pg

157
UNIX

În timp ce gruparea în paranteze şi execuţia în background produc un


singur proces copil, gruparea secvenţială şi cea de tip pipe produc procese
copil multiple. Datorită vitezei operaţiunilor, utilizatorul nu realizează câte
procese sunt generate de fiecare dată. În cazul grupării secvenţiale, shell-ul
generează un proces de execuţie a primei comenzi. Când comanda este
încheiată, shell-ul generează alt proces pentru execuţia celei de-a doua
comenzi, deci procesele sunt generate secvenţial. Gruparea în paranteze se
foloseşte atunci când ieşirile comenzilor sunt trimise către o singură
destinaţie. Este generat în acest caz un singur proces ce este suprapus de
fiecare dată când trebuie executată altă comandă.
Gruparea în conductă se foloseşte atunci când ieşirea primei comenzi
trebuie preluată de a doua comandă ca intrare. Comanda pipe determină
generarea atâtor procese câte comenzi există pe linia de comandă.
Comenzile sunt suprapuse peste aceste procese şi sunt executate.
Comunicarea dintre procesele în execuţie este stabilită de un fişier special
de tip pipe.
Comenzile rulate în background sunt executate în mod normal, adică
procesul este generat de fork şi comanda este executată de exec. Totuşi,
apelul de sistem wait este omis. Aceast lucru permite shell-ului să continue
de îndată ce comanda din background a început. Uneori este necesar ca o
comandă în background să aştepte pâna la terminarea unei alte comenzi din
background înainte ca să fie executat codul. În acest caz este folosită o
combinaţie de wait şi $! ($! conţine identificatorul procesului ultimei
comenzi lansate în background). Secvenţa următoare justifică aceasta:

sort hugefile > outfile1& pid1=$!


sort hugefile > outfile2& pid2=$!
...
wait $pid1
wait $pid2
diff outfile1 outfile2 >&1

7.6.3 Modalităţi de apel al shell-ului

Există două modalităţi de apel al shell-ului: apelul standard şi apelul


la linia de comandă.
Apelul standard se face prin intermediul procedurii de login,
procedură în care se folosesc anumite fişiere şi programe pentru a face
iniţializările configuraţiei utilizatorilor. Spre exemplu, în UNIX System V
se folosesc fişierele /etc/inittab, /etc/profile, /etc/passwd şi .profile.

158
Bourne shell

După ce numele şi parola utilizatorului (preluată din /etc/passwd,


unde este memorată criptat) sunt verificate, programul login foloseşte
informaţia conţinută în /etc/passwd pentru următorul pas din procedură.
Fiecărui utilizator îi este asociată o linie în acest fişier ce conţine numele,
parola, directorul home şi shell-ul implicit ce este apelat la intrarea în
sistem. După ce au fost executate fişierele /etc/profile şi .profile programul
login se suprapune peste sh folosind apelul de sistem exec.
O altă modalitate de apel al shell-ului este de a introduce numele la
linia de comandă. Comanda exec poate fi folosită la linia de comandă,
urmată de numele programului shell ca opţiune:

$ exec -sh

Această comandă asigură faptul că fişierele /etc/profile şi .profile


sunt executate. Comanda nu crează un nou proces ci suprapune programul
sh peste un proces în execuţie. Deoarece constă din execuţia atât a unui fork
cât şi a unui exec, comanda sh creează un nou proces.

7.6.4 Comanda sh

O posibilitate de folosire a acestei comenzi este aceea de a folosi


opţiunea -r prin intermediul căreia se porneşte un shell restricţionat
(rsh - restricted shell). Acest shell reduce posibilităţile de acţiune ale
utilizatorului faţă de acţiunile permise în cadrul shell-ului obişnuit (de
regulă comanda este folosită pentru utilizatorii noi din sistem).
Aceste restricţii sunt:
ƒ Variabilele PATH şi SHELL nu pot fi modificate;
ƒ Comenzile nu pot fi specificate folosindu-se întreaga cale;
ƒ Redirectarea operatorilor este dezactivată (pentru <, >, >>);
ƒ Programele nu pot fi pornite cu exec;
ƒ Comanda cd este dezactivată;

Cu alte cuvinte, rsh dezactivează toate comenzile ce nu sunt în


directorul curent sau în calea standard de căutare, protejează fişierele de
creare sau modificare prin redirectare, asigură protecţia supraîncărcării
shell-ului de către utilizator şi forţează utilizatorul să rămână în directorul
home.
Alte opţiuni ale comenzii:
ƒ Opţiunea -c <sir_caractere> face să se execute comanda
identificată de şirul de caractere;

159
UNIX

ƒ Opţiunea -i face shell-ul interactiv;


ƒ Opţiunea -s permite posibilitatea citirii de comenzi de la intrarea
standard.

7.6.5 Subshell-uri

Este important în UNIX să cunoaştem modul de execuţie a


comenzilor şi shell-script-urilor din punct de vedere al "locului" de rulare a
acestora. Astfel, atunci când o comandă este oferită spre execuţie shell-ului
este creat un subshell, care este un proces copil.
Cea mai uzuală metodă de a rula o comandă este aceea de a
introduce comanda la prompter-ul UNIX. Totuşi, comanda poate fi
executată şi astfel:

$ sh nume_comanda

Fiecare metodă creează de fapt câte un subshell. Ce este important


de ştiut este faptul că modificările aduse mediului de către subshell nu sunt
valabile şi în shell-ul părinte.

7.6.6 Comenzile env şi set

Shell-ul oferă posibilitatea modificării mediului de execuţie prin:


ƒ env
ƒ set
Atunci când folosim env fără argumente, se vor lista doar variabilele
ce au fost moştenite (exportate) de la procesul părinte.

Exemplu:

$ env
VAR=1
EXPORTED=vt100

Atunci când folosim set fără argumente, se aşteaptă o listă a tuturor


variabilelor din mediul shell al utilizatorului (variabile locale sau exportate).

160
Bourne shell

Exemplu:
$set
PATH=/home/razvan:/bin:/usr/bin
TERM=vt220
VAR1=1
EXPORTED=vt100
$

Formatul general al comenzii env este:

$ env [-] [<nume=valoare ...>][<comanda>

Exemplu:

$ env TERM=tvi050 vi myfile

Scopul lui env este modificarea temporară a mediului shell. Atunci


când comanda env este folosită fără semnul minus (-), preia mediul curent şi
îl modifică în concordanţă cu atribuirile specificate, executând apoi
comanda ce apare în mediul temporar. Dacă apare semnul minus (-), mediul
moştenit este ignorat şi se execută comanda respectivă folosind mediul
specificat.
Formatul general al lui set este:

$ set [optiuni] [argumente]

Atunci când sunt specificate valori drept argumente, sunt setate


valorile parametrilor poziţionali corespunzători. Atunci când set este folosită
cu opţiuni, ea modifică execuţia shell-ului curent. Opţiunile sunt activate
dacă sunt precedate de semnul minus (-) şi dezactivate când sunt precedate
de semnul plus (+).
Una dintre utilizările de bază ale comenzii set este aceea de depanare
a shell-script-urilor folosind opţiunea -v care urmăreşte execuţia
shell-script-ului. Opţiunile existente pentru comanda set sunt:
ƒ -a exportă în mod automat toate variabilele ce sunt definite sau
modificate;
ƒ -e iese dacă o comandă returnează un exit-status false;
ƒ -f dezactivează generarea numelui de fişier;
ƒ -n citeşte comenzile fără să le execute;

161
UNIX

ƒ -u generează o eroare dacă o variabilă este referită înainte de a fi


definită;
ƒ -v tipăreşte fiecare linie de comandă shell înainte de a fi folosită;
ƒ -x tipăreşte comenzile şi argumentele lor atunci când sunt
folosite;
ƒ - dezactivează opţiunile x şi v.
Fie shell-script-ul denumit test:
set -x
cmd=wc
cat fisier | $cmd -l

Execuţia shell-script-ului este:


$
+ cat fişier
+ wc -l 33
$

Un shell-script poate stabili care dintre opţiunile set sunt activate


folosind variabila specială $-.
Semnificaţia semnalelor recunoscute în UNIX
Tabelul 7.1
Numărul
Semnal Semnificaţie
semnalului
0 semnal special shell ce determină execuţia
unei comenzi la ieşirea din shell
1 SIGHUP terminal hangup
2 SIGINT întrerupere (DEL - tastă apăsată)
3 SIGQUIT quit (s-a apăsat CTRL+\)
4 SIGILL instrucţiune ilegală
5 SIGTRAP trace/breakpoint trap
6 SIGABORT abort
7 SIGEMT emulation trap
8 SIGFPE excepţie aritmetică
9 SIGKILL semnal kill
10 SIGBUS eroare bus
11 SIGSEGV segmentation fault
12 SIGSYS bad system call
13 SIGPIPE broken pipe
14 SIGALARM alarm clock
15 SIGTERM terminated

162
Bourne shell

7.6.7 Semnale

Este necesar uneori ca shell-script-ul să poată fi întrerupt pentru a ne


întoarce la prompter. Putem apăsa DELETE, BREAK sau CTRL+C. În
funcţie de necesităţi, uneori este necesar să executăm o operaţie de
întreţinere atunci când un shell-script este întrerupt (trebuie să închidem sau
să ştergem fişierele temporare). În alte circumstanţe, se poate dori
îndeplinirea unei anumite sarcini fără întrerupere. UNIX oferă posibilitatea
manevrării exprese a evenimentelor iniţiate de lumea din afară prin folosirea
semnalelor. În funcţie de versiunea de UNIX utilizată, numărul de semnale
recunoscute variază între 15 şi 30. Lista acestora este prezentată în
tabelul 7.1. Semnalele 1..9 şi 15 sunt relevante pentru programatorul Shell.
Celelalte apar pentru completitudine şi pentru a arăta ce fel de semnale pot
fi manipulate de UNIX.

Observaţie.
De regulă, semnalele sunt interceptate de apelul de sistem signal ce
poate fi folosit în programe C.
Exemplu:
Fie o instrucţiune dintr-un program C ce face o împărţire la zero:
printf("Impartire la zero:%d",6/0);
În acest caz este semnalat un SIGFPE, iar programul trebuie să
includă cod care să recepţioneze acest semnal: signal(SIGFPE,f_cleanup),
unde f_cleanup este funcţia ce rezolvă problema şi afişează un mesaj
corespunzător.
Comanda trap
O altă modalitate de interceptare a mesajelor este aceea realizată prin
intermediul comenzii interne trap. Această comandă permite interceptarea şi
prelucrarea semnalelor ce ar afecta shell-script-ul într-o manieră
imprevizibilă.
Formatul general al comenzii este:

$ trap comenzi semnale

unde comenzi reprezintă comenzi ce se execută la apariţia unuia


dintre semnale. Fie comanda:

$ trap "rm tmp*;echo interrupt!;exit 3" 1 2

163
UNIX

Această comandă poate inhiba întreruperile în cazul proiectării unor


interfeţe prietenoase cu utilizatorii. De exemplu, o interfaţă utilizator poate
să ignore apăsarea tastelor DEL, BREAK sau CTRL+C. Următoarea
comandă face ca semnalele respective să fie ignorate:

$ trap "" 1 2 3 15

Atunci când trap este folosită pentru a ignora semnale, afectează


toate subshell-urile. Când trap este folosită să ia acţiune, nu le afectează.
Dacă se doreşte ca acţiunea lui trap să aibă efect în subshell-uri, trebuie
specificat în mod explicit acest lucru în fiecare subshell. Totuşi, nu orice
semnale pot fi ignorate; în caz contrar nu ar mai putea fi intrerupte anumite
programe sub nici o formă!
Există SIGKILL care nu poate fi ignorat! Acest semnal este generat
de comanda internă kill.

Exemplu:

$ kill -9 12345

unde 12345 este identificatorul procesului ce trebuie terminat.

7.7 Comenzi interne

7.7.1 Introducere

Comenzile înglobate sau interne (built-in commands) sunt comenzi


ce pot fi apelate din interiorul unui shell-script sau de la linia de comandă.
Shell-ul are 32 de comenzi înglobate. Fiecare comandă ce este executată
returnează un cod de ieşire denumit exit-code sau exit-status. Atunci când
comanda nu se termină pe o singură linie, shell-ul prezintă cel de-al doilea
prompter (al doilea prompter este implicit semnul mai mare (>))
utilizatorului pentru introducerea caracterelor de continuare până când se
încheie comanda.

164
Bourne shell

Exemplu:
$ for i in f1 f2
>do
>file $i
>done
$

7.7.2 getopts

Există posibilitatea ca un shell-script să fie apelat cu opţiuni. Dacă


un shell-script denumit test.cmd are următoarea sintaxă:

$ test.cmd [-a] [-b] [-c]

atunci el poate fi apelat în oricare dintre modalităţile următoare:

$ test.cmd -a
$ test.cmd -abc
$ test.cmd
$ test.cmd -a -b
$ test.cmd -a -b -c

ş.a.m.d
În acest caz vom folosi getopts în interiorul uneia dintre
instrucţiunile for, while sau until. Comanda getopts returnează valoarea
logică "true" atât timp cât există opţiuni ce trebuie luate în considerare.
Formatul general al comenzii este:

$ getopts optiuni nume_variabila

165
UNIX

Exemplu.
Fie shell-script-ul test.cmd:

# test.cmd
...
while getopts abc optiune
do
...
done

Care este modalitatea de lucru a lui getopts? Spre exemplu, dacă


apelul s-a făcut test.cmd -abc, comanda getopts verifică prima dată dacă
există simbolul minus (-) în linia de comandă. Verifică apoi dacă litera ce
urmează este una dintre opţiunile valide. Dacă opţiunea este validă, atunci
ea este memorată în variabila optiune. În acest moment este returnat un exit
status cu valoarea zero, deci corpul ciclului while este executat. Opţiunile
următoare sunt tratate în mod asemănător. Atunci când se epuizează toate
opţiunile, getopts returnează o valoare diferită de zero şi astfel ciclul while
se încheie.
În cazul apariţiei unei opţiuni invalide, spre exemplu se face apelul
test.cmd -abcd, opţiunile corecte sunt tratate ca mai sus, iar opţiunea
invalidă d este considerată şi ea de getopts deoarece face parte din grupul
precedat de semnul minus (-). În acest caz, getopts ia valoarea specială ?,
apoi returnează un exit status de valoare zero şi corpul ciclului while este
executat. Shell-script-ul va conţine cod corespunzător pentru fiecare opţiune
validă. Un exemplu ar putea fi acela construit cu un case:

while getopts abc optiune


do
case “$optiune” in
a) ...;;
b) ...;;
c) ...;;
\?) echo "Optiune invalida..."
esac

done

166
Bourne shell

Fie un nou shell-script, cu următorul format:

$ test2.cmd [-a] [-b] [-c] infocib

Opţiunile a,b şi c sunt tratate ca mai înainte iar getopts întoarce o


valoare diferită de zero deoarece argumentul infocib nu este o opţiune.
Ciclul se termină drept rezultat al apariţiei unei valori false (diferită de zero)
iar argumentul infocib este luat în considerare în continuare, după ciclul
getopts.
Fie acum cazul în care o opţiune necesită şi un argument ce trebuie
specificat. Fie shell-script-ul:

$ test3.cmd [-a] [-b argument] nume_fisier

Comanda getopts devine: getopts ab: opţiune, unde apariţia


semnului două puncte (:) înseamnă că această opţiune trebuie urmată de cel
puţin un caracter whitespace şi de un argument. Argumentul va fi memorat
într-o variabilă specială numită OPTARG.
Dacă linia de comandă conţine -b fără nici un argument în
continuare, în variabila opţiune este memorat un semn de întrebare (?). O
altă variabilă specială, numită OPTIND este incrementată de fiecare dată
când getopts returnează o valoare. Ea are iniţial valoarea 1. Se poate verifica
în acest mod dacă a fost introdus argumentul specificat pentru execuţia
corectă a comenzii. Astfel, în apelul test3.cmd -a -b nume infocib, dacă
valoarea lui OPTIND este mai mare decât valoarea lui $#, atunci numele
fişierului nume_fisier pentru execuţia corectă a scriptului nu a fost introdus.

7.7.3 Comanda hash

Comanda hash este folosită pentru mărirea vitezei primirii


comenzilor. Sintaxa generală a acestei comenzi este:

$ hash [-r] comenzi

167
UNIX

Acest apel al comenzii "spune" shell-ului să caute comanda sau


comenzile specificate şi să adauge directorul în care sunt localizate acestea
la "lista hash". Spre exemplu, odată executată comanda:

$ hash inter

următoarele apeluri către shell-script-ul inter se vor executa cu


viteză mai mare. Dacă folosim comanda hash fără nici un argument, se va
afişa o listă cu comenzi ce sunt deja în lista hash. Opţiunea -r se foloseşte
atunci când dorim ştergerea din listă a unei comenzi.
Comanda hash -r şterge toate componentele listei. Comanda hash
fără nici un argument afişează toate componentele listei.

7.7.4 Comanda type

Comanda type afişează informaţii despre comanda sau comenzile


specificate, având sintaxa:

$ type comenzi

Comanda type poate fi folosită împreună cu:


ƒ comenzi interne
ƒ comenzi UNIX
ƒ shell-script-uri
ƒ funcţii

7.7.5 Comanda newgrp

Comanda newgrp modifică pentru un utilizator UNIX identificatorul


de grup (group_id). Sintaxa generală este:

$ newgrp [nume_grup]

Presupunând că grupul utilizatorului se intitulează cibernetica şi


trebuie schimbat în comert, comanda este: newgrp comert.
Pentru motive legate de securitatea sistemului, modificarea este
permisă doar dacă utilizatorul apare în lista membrilor grupului comert din

168
Bourne shell

fişierul /etc/group. Cu ajutorul acestei modificări, utilizatorul poate accesa


programe disponibile grupului comert.

7.7.6 ulimit

Dimensiunea fişierului pe care un proces copil îl poate scrie este


limitată de un anumit număr de blocuri folosind comanda ulimit. Sintaxa
generală a acestei comenzi este:

$ ulimit dimensiune_fisier

Pentru a afla setarea curentă, introducem pur şi simplu comanda fără


nici un argument. Utilizatorul obişnuit poate micşora dimensiunea; doar
root poate creşte această dimensiune.

7.7.7 umask

Comanda umask determină drepturile de acces implicite la fişiere


(default mask). Acestea sunt create folosind valori octale. Pentru un fişier
obişnuit, drepturile de acces deplin sunt de forma: -rw-rw-rw-, iar valoarea
octală a reprezentării este 666. Dreptul de acces pentru un anumit fişier se
obţine scăzând din 666 valoarea lui umask.
În general, valoarea lui umask este setată de root la valoarea octală
022. Se obţine astfel valoarea 666-022=644, care reprezintă drepturile
implicite pentru fişierele nou create: -rw-r--r--. Dacă dorim drepturi depline
de acces, vom seta umask la valoarea 0, prin comanda umask 0. Pentru un
director, drepturile depline de acces sunt: -rwxrwxrwx (777 în octal).
Dreptul x (de execuţie) pentru un director oferă utilizatorului dreptul
de citire a conţinutului directorului. Astfel, dreptul de acces la director se
obţine scăzând din 777 valoarea lui umask: 777-022=755, care reprezintă
drepturile: -rw-r-xr-x.

7.7.8 Comanda times

Comanda times se foloseşte pentru afişarea de către shell a timpului


necesitat de toate procesele rulate de către acesta. Sunt listate atât timpul
utilizator cât şi cel sistem. Fie exemplul:
$ times
0m30s 3m30s

169
UNIX

Primul timp reprezintă 30 de secunde petrecute în mod utilizator iar


cel de-al doilea timp este timpul ce a fost alocat proceselor sistem.

7.7.9 Comanda eval

Comanda eval asigură evaluarea completă a unei variabile.

Exemplu:
$ dir_curent=’$pwd’
$ echo $dir_curent
$ pwd

În cazul utilizării comenzii eval vom obţine următorul rezultat:


$ eval $dir_curent
/home/stud/an3/i97aaa

7.8 Crearea unui shell-script

Pentru a crea un shell-script avem nevoie de un editor de text cu care


putem insera comenzi shell într-un fişier. Este bine să introducem în cadrul
script-ului pe lângă comenzile folosite şi comentarii, pentru a face înţeles
rolul comenzilor şi scopul shell-script-ului. Comentariile se introduc
folosindu-se simbolul special diez (#).
Tot ce urmează după simbolul # până la capătul rândului pe care se
găseşte acesta este considerat comentariu. Excepţie face prima linie din
program, care indică tipul programului shell ce va executa liniile din script
(sh, csh, bash etc.). Astfel, în cazul utilizării shell-ului Bourne, prima linie
din script va fi:

#!/bin/sh

Aici semnul special # nu mai are rolul de început de comentariu, ci


împreună cu semnul exclamării (!) formează un „număr magic” - #! - ce
specifică kernel-ului să identifice programul ce va interpreta shell-script-ul
respectiv. Această linie trebuie neapărat să se afle la începutul programului

170
Bourne shell

(pe prima linie din script). În cazul folosirii shell-ului Bash din Linux, prima
linie dintr-un shell-script va arăta astfel:
#!/bin/bash

După ce am creat fişierul shell-script ce poate conţine comenzi


shell, comenzi UNIX sau comentarii, trebuie să facem acest fişier
executabil. Acest lucru se realizează folosind comanda UNIX chmod.
Spre exemplu, dacă shell-script-ul nostru se intitulează
program_shell, atunci comanda prin care acest fişier devine executabil este:

$ chmod +x program_shell

7.9 Depanarea programelor shell

Utilizarea opţiunii –n la apelul comenzii sh ne oferă posibilitatea


verificării sintaxei unui shell-script fără a executa vreuna din comenzile
acestuia. Dacă există vreo eroare de sintaxă în cadrul script-ului, shell-ul va
semnaliza acea eroare. În caz contrar, înseamnă că programul este corect din
punct de vedere sintactic şi nu se va afişa nimic.

Opţiuni de depanare pentru Bourne Shell


Tabelul 7.2
Denumirea
Comanda Explicaţii
opţiunii
Afişează fiecare linie a script-ului
Opţiunea echo sh –x nume_script după substituirea variabilelor,
înaintea execuţiei
Afişează fiecare linie a script-ului
Opţiunea verbose sh –v nume_script înaintea execuţiei, exact aşa cum a
fost scrisă
Interpretează dar nu execută
Opţiunea noexec sh –n nume_script
comenzile
Setează echo-ul set –x Urmăreşte execuţia unui script
Opreşte urmărirea execuţiei unui
Resetează echo-ul set +x
script

Cel mai des se foloseşte opţiunea –x a comenzii set pentru depanarea


script-urilor, sau se poate apela direct comanda sh cu opţiunea –x. Utilizând
această opţiune, se va afişa fiecare comandă din shell-script (după ce s-a

171
UNIX

făcut în prealabil substituirea valorilor variabilelor) şi apoi este executată.


Atunci când se afişează o linie din shell-script, este precedată de semnul
plus (+).
O altă opţiune folosită este opţiunea –v (verbose) “vorbăreaţă”
(sh –v nume_script) când se afişează fiecare linie din shell-script ca şi cum
ar fi fost scrisă la linia de comandă iar după aceea este executată. În tabelul
7.2 sunt prezentate opţiunile folosite pentru depanare în cazul shell-ului
Bourne.

7.10 Exemple de programe Bourne shell

Exemplul 1.

iesire=F
while [ $iesire = "F" -o $iesire = "f" ]
do
clear
echo "Alegeti o opţiune:"
echo
echo "1. Lansare Midnight Commander"
echo "2. Editare cu Nice Editor"
echo "3. Afisare cale curenta"
echo "4. E-mail"
echo "5. Afisarea numarului de utilizatori
conectati la\ sistem"
echo "0. Iesire"
echo
read optiune
case $optiune in
1) mc ;;
2) echo "Nume fişier de editat: "
read fis
if [ -f $fis ]
then
ne $fis
else
echo "Fişier inexistent. Il\
creati?(d/n)"
read rasp
if [ $rasp = "d" ]
then
ne $fis
fi
fi ;;
3) pwd
echo "Apasati o tasta pentru continuare..."
read y ;;

172
Bourne shell

4) echo "Introduceti adresa destinatarului:"


read adresa
mail $adresa
echo "Apasati o tasta pentru continuare..."

read y ;;
5) echo "Sunt conectati `who | wc -l`\
utilizatori in acest moment!"
echo "Apasati o tasta pentru continuare..."

read y ;;
0) iesire=D ;;
esac
done

Explicaţii.
Programul afişează un meniu cu 6 opţiuni. Opţiunea este citită în
variabila optiune şi în funcţie de valoarea acesteia se execută comenzile
specificate folosindu-se o instrucţiune case. Totul este inclus într-un ciclu
while, care se va repeta până în momentul selectării opţiunii 0, când
variabila iesire ia valoarea D şi se iese astfel din ciclul while.

Exemplul 2.
În acest exemplu vom lucra cu o bază de date simplă – vom crea
funcţii pentru adăugare, ştergere, actualizare şi un program principal ce
apelează aceste funcţii. Baza noastră de date va conţine informaţii despre
studenţii unei facultăţi: nume şi prenume, grupa, adresa, şi data naşterii.
Fişierul ce va conţine aceste informaţii se va numi studenti.
Să presupunem că vom defini funcţiile în fişierul functii.
Fie funcţia de adăugare:

adaug () { # Functia este definita in fisierul functii


while true
do
echo "Adaugare de informatii… "
echo "Introduceti numele si prenumele studentului "
read nume
echo "Introduceti grupa "
read grupa
echo "Introduceti adresa "
read adresa
echo "Introduceti data nasterii (zz/ll/aaaa) "
read datan
echo $nume:$grupa:$adresa: $datan

173
UNIX

echo "Datele sunt corecte? "


read ans
case "$ans" in
[Dd]*)
echo "Adaugarea informatiilor..."
echo $nume:$grupa:$adresa: $datan >> studenti
sort -u studenti -o studenti
echo "Vreti sa continuati introducerea? "
read ans
if [ $ans = D -o $ans = d ]
then
return # revenire in programul apelant
else
continue # salt la inceputul ciclului
fi
;;
*)
echo "Incercati din nou?(D/N) "
read answer
case "$answer" in
[Dd]*)
continue;;
*)
exit;;
esac
;;
esac
done
} # Sfarsitul definitiei functiei

Programul principal ce va apela funcţiile de adăugare, ştergere,


actualizare va arăta astfel:
#!/bin/sh
# Numele script-ului: program
# Acest shell-script va apela functiile

#fisier=$HOME/studenti
fisier=./studenti

.functii # Comanda punct citeşte fis functii în memorie


if [ ! -f $fisier ]
then
echo "`basename $fisier` nu exista" 1>&2
exit 1
fi
echo "Selectati optiunea: "

174
Bourne shell

cat <<EOF
[1] Adaugare de informatii
[2] Stergere de informatii
[3] Actualizarea informatiilor
[4] Iesire din program
EOF
read optiune
case $optiune in
1) adaug # Apelul functiei adaug
;;
2) sterg # Apelul functiei sterg
;;
3) actualizare # Apelul functiei actualizare
;;
4) echo La revedere!
exit 0
;;
*) echo Optiune gresita!
exit 2
;;
esac
echo Intoarcere din apelul functiei

Funcţiile de ştergere şi de actualizare se lasă ca temă.

175
1. Bourne Again Shell

8 BOURNE AGAIN SHELL

8.1 Introducere

Bourne Again Shell (bash) oferă o serie de facilităţi în plus faţă de


shell-ul standard Bourne, atât la nivel de interpretor al liniei de comandă, cât
şi la nivel de limbaj de programare. Printre altele, bash oferă istoric al
comenzilor, alias-uri, auto-completarea comenzilor şi a numelor de fişiere,
editarea liniei de comandă, etc. Unele dintre aceste facilităţi sunt prezente şi
în shell-ul standard Bourne, însă proiectul GNU a extins shell-ul pentru a
include un număr de noi facilităţi şi pentru compatibilitate POSIX.
O dată cu realizarea variantei bash 2.x, au fost adăugate atât de multe
funcţionalităţi (unele din Korn shell şi C shell), încât shell-ul bash
reprezintă un shell complect funcţional atât la nivel de interpretor cât şi la
nivel de limbaj de programare. Shell-ul bash s-a născut pe 10 ianuarie 1988
sub oblăduirea lui Brian Fox şi a fost adoptat mai târziu de către Chet
Ramey. Prima versiune a fost versiunea bash 0.99, iar cele mai importante
îmbunătăţiri au fost aduse odată cu versiunea 2.0. Toate versiunile sunt
disponibile free sub licenţă publică GNU. Pentru a vedea ce versiune de
bash foloseşte, un utilizator poate folosi comanda bash --version sau poate
afişa valoarea variabilei de mediu BASH_VERSION. Următorul exemplu ne
înfăţişează o posibilă situaţie:

$ bash --version
GNU bash, version 2.04.11(1)-release (i386-redhat-linux-gnu)
Copyright 1999 Free Software Foundation, Inc.

$ echo $BASH_VERSION
2.04.11(1)-release

176
UNIX

8.2 Iniţializare şi mediu

În momentul iniţializării, shell-ul bash parcurge o serie de paşi.


Primul proces ce se rulează în momentul iniţializării este init, cu
identificatorul PID=1. Acest proces iniţiază un proces getty, care deschide
porturile terminalului, oferind un “spaţiu de manevră” pentru standard input
şi pentru standard output şi standard error. În urma acestui proces va fi
afişat un prompter de login pe ecran. În continuare se execută programul
/bin/login, care cere o parolă, criptează şi verifică parola, setând un mediu
iniţial de lucru şi pornind shell-ul de login (care în cazul nostru este
/bin/bash).
După aceea, procesul (programul) bash caută fişierul de configurare
/etc/profile şi execută comenzile din acesta. În continuare, se caută în
directorul home un fişier de configurare iniţială denumit .bash_profile. După
executarea comenzilor din acest fişier, se va executa o comandă din fişierul
ENV al utilizatorului, de regulă .bashrc şi, în cele din urmă, prompter-ul
(semnul $ pentru utilizatorul obişnuit sau # pentru root) este afişat pe ecran,
aşteptând introducerea de comenzi.
Dacă dorim modificarea shell-ului la linia de comandă, putem să
introducem simplu numele shell-ului şi să apăsăm ENTER. De exemplu,
dacă folosim la un moment dat shell-ul standard Bourne şi dorim să
schimbăm în Bourne Again shell, nu avem decât să introducem bash la linia
de comandă, urmat de tasta ENTER:

$ ps
PID TTY TIME CMD
5549 tty1 00:00:00 sh
5429 tty1 00:00:00 ps

$ bash
bash-2.04$

bash-2.04$ ps
PID TTY TIME CMD
5449 tty1 00:00:00 sh
5465 tty1 00:00:00 bash
5472 tty1 00:00:00 ps

Explicaţii. Iniţial, comanda ps (process status) ne arată procesele


aflate în execuţie. Se observă că rulează shell-ul Bourne (sh). Se introduce
apoi comanda bash la prompter şi apare un nou prompter (bash-2.04$).

177
Bourne again shell

Introducând din nou comanda ps, se afişează de data aceasta două shell-uri
care rulează: shell-ul iniţial sh şi shell-ul bash pornit ulterior.

Fişiere de iniţializare
Shell-ul bash are o serie de fişiere de configurare pe care le verifică
la pornire. Aceste fişiere de configurare sau iniţializare sunt procesate
(rulate) în funcţie de mai multţi factori (dacă shell-ul curent este şi shell-ul
de login, dacă este un alt shell interactiv diferit decât cel de login, sau un
shell non-interactiv - shell-script). Să vedem în continuare care sunt fişierele
de configurare iniţială şi ordinea în care aceste fişiere sunt procesate.
În momentul login-ului, înainte de apariţia prompter-ului shell, este
executat fişierul de configurare globală, /etc/profile. După aceea, dacă
există, este procesat fişierul .bash_profile din directorul home al
utilizatorului. Acest fişier specifică alias-uri şi funcţii şi setează variabile de
mediu specifice utilizatorului sau porneşte anumite shell-script-uri. Dacă
fişierul .bash_profile nu există, dar există fişierul .bash_login, atunci acest
fişier va fi procesat, iar dacă acesta din urmă nu există, va fi procesat fişierul
.profile (din directorul home al utilizatorului).

8.2.1 Fişierul /etc/profile

Fişierul /etc/profile reprezintă un fişier de configurare globală a


întregului sistem. Acest fişier este editat de către administratorul sistemului
pentru a executa anumite comenzi atunci când se iniţializează sistemul. El
este executat atunci când porneşte shell-ul bash. El are acelaşi efect şi în
cazul shell-urilor Korn şi Bourne şi, de regulă, îndeplineşte anumite sarcini
precum rularea programului ce administrează mailul (mail spooler) sau
afişarea unui mesaj iniţial, denumit „mesajul zilei” (message of the day, din
fişierul /etc/motd). În continuare este prezentat un exemplu de fişier
/etc/profile (nu am numerotat liniile goale):

1 #/etc/profile
2 # System wide environment and startup programs
3 # Functions and aliases go in /etc/bashrc

4 PATH=”$PATH:/usr/X11R6/bin”

5 ulimit -S -c 1000000 > /dev/null 2>&1


6 if [ ‘id -gn’ = ‘id -un’ -a ‘id -u’ -gt 14 ]; then
7 umask 002
8 else

178
UNIX

9 umask 022
10 fi
11 USER=’id -un’
12 LOGNAME=$USER
13 MAIL=”/var/spool/mail/$USER”
14 HOSTNAME=`/bin/hostname`
15 HISTSIZE=1000

16 if [ -z “$INPUTRC” -a ! -f “$HOME/.inputrc” ]; then


17 INPUTRC=/etc/inputrc
18 fi
19 export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC

20 for i in /etc/profile.d/*.sh ; do
21 if [ -x $i ]; then
22 . $i
23 fi
24 done
25 unset i

Prezentăm în continuare câteva explicaţii analizând fişierul


/etc/profile pe linii:
Liniile 1,2,3 - Comentarii în shell-script;
Linia 4 - Variabilei PATH i se atribuie directoarele unde va căuta
shell-ul comenzile introduse;
Linia 5 - Comanda ulimit stabileşte limita maximă a dimensiunii
fişierelor core la 1.000.000 bytes. Fişierele core sunt fişiere create în urma
opririi anormale a programelor şi pot ocupa dimensiuni considerabile din
spaţiul de pe disc;
Liniile 6-10 - Comanda if care realizează următoarele: „dacă numele
grupului este egal cu numele utilizatorului şi numărul ID al utilizatorului
este mai mare decât 14”, atunci setează umask cu valoarea 002. În acest caz,
atunci când sunt create directoarele vor avea drepturi de acces 775 iar
fişierele vor avea 664. Altfel, umask va avea valoarea 022, de unde rezultă
drepturi 755 pentru directoare şi 644 pentru fişiere.
Linia 11 - Variabilei USER i se atribuie valoarea pe care o returnează
comanda id -un (numele utilizatorului)
Linia 12 - Variabilei LOGNAME i se atribuie valoarea din $USER;
Linia 13 - Variabila MAIL ia valoarea egală cu numele directorului
unde se programul de administare a mail-ului va salva mail-ul;
Linia 14 - Variabila HOSTNAME ia valoarea numelui maşinii;
Linia 15 - Variabila HISTSIZE ia valoarea 1000 (numărul de
comenzi stocate în memoria history);

179
Bourne again shell

Liniile 16-18 - Comanda if care verifică dacă fişierul cu numele dat


de variabila INPUTRC are dimensiunea diferită de zero şi nu există fişierul
.inputrc din directorul home şi în acest caz variabila INPUTRC ia valoarea
/etc/inputrc;
Linia 19 - Variabilele ce apar în această linie sunt „exportate” pentru
a fi disponibile în sub-shell-uri şi procese copil;
Linia 20-24 - O comanda for şi una if care realizează următoarele:
pentru fiecare fişier cu extensia .sh din directorul /etc/profile.d, se verifică
dacă este executabil, iar dacă este executabil, se execută fişierul
utilizându-se comanda dot (.). Fişierele din directorul /etc/profile.d, lang.sh
şi mc.sh, setează setul de caractere şi de fonturi şi crează o funcţie denumită
mc (Midnight Commander) care reprezintă un browser (asemănător cu
vestitul Norton Commander pentru DOS/Windows) vizual de fişiere. Pentru
pornirea acestuia se scrie mc la linia de comandă.
Linia 25 - Variabila i este resetată prin comanda unset, adică ştearsă
din memoria shell-ului.

8.2.2 Fişierul .bash_profile

Dacă fişierul .bash_profile este găsit în directorul home al


utilizatorului, atunci este executat imediat după /etc/profile. Dacă
.bash_profile nu există, atunci shell-ul bash va căuta fişierul .bash_login
sau, dacă nici acesta nu există, fişierul .profile, toate din directorul home.
Doar unul dintre cele trei fişiere menţionate anterior va fi executat, iar
căutarea se face în ordinea specificată (bash_profile, .bash_login, .profile).
De asemenea, bash va verifica existenţa fişierului .bashrc şi îl va executa
comenzile din acesta dacă fişierul există. Prezentăm în continuare un
exemplu de fişier .bash_profile:

1 #.bash_profile
2 # Get the aliases and functions

3 if [ -f ~/.bashrc ]; then
4 . ~/.bashrc
5 fi

6 PATH=$PATH:$HOME/bin
7 BASH_ENV=$HOME/.bashrc
8 USERNAME=”razvan”
9 export USERNAME BASH_ENV PATH
10 mesg n

180
UNIX

Prezentăm în continuare câteva explicaţii analizând fişierul


.bash_profile pe linii:
Liniile 1,2 - Comentarii în shell-script;
Liniile 3-5 - Comandă if care verifică dacă fişierul .bashrc se află în
directorul home şi dacă există îl rulează;
Linia 6 - Variabilei PATH i se adaugă o cale către subdirectorul bin
din directorul home;
Linia 7 - Variabilei BASH_ENV i se atribuie valoarea specificată
(calea către fişierul .bashrc). Fişierul .bashrc conţine funcţii şi alias-uri
definite de utilizator;
Linia 8 - Variabila USERNAME ia valoarea razvan;
Linia 9 -Variabilele specificate sunt exportate pentru a fi valabile în
subshell-uri şi procese copil;
Linia 10 - Comanda mesg executată cu opţiunea n are ca efect
blocarea mesajelor primite cu comanda write de la alţi utilizatori.

8.2.3 Fişierul .bashrc

Fişierul .bashrc este automat executat ori de câte ori un shell bash
porneşte, conţinând numai setări valabile pentru shell-ul bash.
Avem în continuare un exemplu de fişier .bashrc:

1 #.bashrc
2 # User specific aliases and functions
3 # Source global definitions

4 if [ -f /etc/bashrc ]; then
5 . /etc/bashrc
6 fi

7 set -o noclobber
8 alias mv=’mv -i’
9 alias dir=’ls -al’
10 function cd { builtin cd $1; echo $PWD; }

Explicaţii:
Liniile 1,2,3 - Comentarii în shell-script;
Liniile 4-6 - Comandă if care verifică existenţa fişierului /etc/bashrc
şi în acest caz îl rulează;
Linia 7 - Comanda set apelată cu opţiunea noclobber determină
apariţia unor mesaje preventive în cazul suprascrierii fişierelor deja
existente;
181
Bourne again shell

Linia 8 - Se declară un alias pentru comanda mv, astfel încât de


acum încolo ea va fi apelată automat cu opţiunea -i(interactive);
Linia 9 - Se declară un alias pe nume dir, care va efectul apelului
comenzii ls -al;
Linia 10 - Se defineşte o funcţie utilizator. Când utilizatorul va
schimba directorul curent se va afişa şi directorul curent de lucru. Numele
fucnţiei este cd şi conţine comanda internă cd (change directory). Comanda
internă builtin precede numele comenzii cd pentru a preveni intrarea în
recursivitate infinită a funcţiei.

8.2.4 Fişierul .profile

Fişierul .profile este un fişier de configurare definit de utilizator. El


se găseşte în directorul home al utilizatorului şi este executat imediat dacă
shell-ul de login este shell-ul Bourne. În cazul în care shell-ul de login este
bash, fişierul .profile va fi rulat doar dacă nici unul din fişierele enumerate
anterior nu există. Fişierul conţine de regulă setări ale mediului şi ale
terminalului sau alte setări legate de diverse aplicaţii, dacă acestea sunt
necesare.
Avem în continuare un exemplu de fişier .profile:

1 #.profile
2 # Fisier de configurare initiala ce se executa atunci cand
3 # se utilizeaza shell-ul sh sau nu exista fisierele
4 # .bash_profile sau .bash_login

5 HOSTNAME=`uname -n`
6 EDITOR=/bin/vi
7 PATH=/bin:/usr/bin:/usr/ucb:/usr/local:/usr/bin:.
8 PS1=”$HOSTNAME $> ”
9 export TERM HOSTNAME EDITOR PATH PS1
10 stty erase ^h
11 clear

Explicaţii:
Liniile 1-4 - Comentarii în shell-script;
Linia 5 - Variabila HOSTNAME va lua valoarea returnată de
comanda uname -n;
Linia 6 - Variabila EDITOR ia valoarea /bin/vi. Programe precum
mail şi history vor folosi acest editor;
Linia 7 - Variabila PATH este setată;
Linia 8 - Prompter-ului primar îi este atribuită valoarea lui
HOSTNAME (numele maşinii), urmată de semnul $ şi semnul >;
182
UNIX

Linia 9 - Sunt exportate variabilele specificate, pentru a fi valabile în


subshell-uri şi procese copil;
Linia 10 - Comanda stty setează caracteristicile terminalului. Tasta
Erase este setată cu valoarea ^h, astfel încât când vom apăsa tasta
Backspace, litera de dinaintea cursorului va fi ştearsă;
Linia 11 - Comanda clear şterge conţinutul ecranului.

8.3 Programarea în bash

Scrierea unui shell-script în bash este similară cu operaţia în Bourne


Shell. Un shell-script se scrie cu ajutorul unui editor şi conţine comenzi
UNIX, comentarii şi cuvinte cheie de programare shell. Deoarece utilizăm
shell-ul bash, prima linie din shell-script va fi:

#!/bin/bash

De asemenea, script-ul trebuie să fie executabil, de aceea vom folosi


comanda chmod pentru a îl face executabil. În exemplul următor
presupunem că script-ul se numeşte script01:

$ chmod +x script01
$ ls -lF script01
-rwxr-xr-x 1 razvan 12 Aug 12:00 script01*

8.3.1 Citirea variabilelor

Citirea variabilelor se face ca şi în shell-ul clasic cu comanda read.


Comanda read preia caractere de la tastatura până când se întâlneşte un
caracter newline. Caracterul (newline) de sfârşit de linie este transformat
într-un octet null atunci când este citit. Dacă nu se specifică nici un nume
pentru variabilă, linia citită este atribuită unei variabile interne, numită
REPLY. Putem, de asemenea, folosi comanda read pentru a face un program
să se oprească în momentul în care apăsăm tasta ENTER. Opţiunile
comenzii read sunt prezentate în tabelul 8.1. De exemplu, opţiunea -r este
folosită pentru ignorarea perechii backslash/newline, astfel încât caracterul
special backslash este considerat ca parte din linie.

183
Bourne again shell

Opţiunile comenzii read

Tabelul 8.1
Comanda Semnificaţie
read raspuns Se citeşte de la tastatură în variabila raspuns
read r1 r2 Se citeşte de la tastatură în variabila r1 până la primul
caracter whitespace sau Enter, apoi în variabila r2
read Se citeşte în variabila internă REPLY
read -a nume_vector Se citeşte o listă de cuvinte într-un vector denumit
nume_vector
read -e Se foloseşte în shell-ul interactiv
read -p prompter Afişează un prompter, aşteaptă input-ul şi stochează
rezultatul în variabila REPLY
read -r linie Permite introducerea liniilor ce conţin un backslash

8.3.2 Operaţii aritmetice

Variabilele pot fi declarate ca numere întregi cu ajutorul comenzii


declare -i. O variabilă numar poate fi declarată astfel:

$ declare -i numar

Se pot face operaţiile aritmetice uzuale cu variabilele declarate


întregi, folosind operatorii pentru adunare, scădere, înmulţire, împărţire şi
împărţire modulo. Exemple:

$ declare -i numar
$ numar=3+7
$ echo $numar
10
$ numar= 6 + 9
bash: +: command not found
(caracterele whitespace trebuie incadrate de
ghilimele, corect este: numar=”6 + 9”)
$ numar=4*5
$ echo $numar
20

184
UNIX

Comanda declare -i fără nici un argument va lista toate variabilele


întregi definite, precum şi valorile lor, ca în exemplul următor:

$ declare -i
declare -ir EUID=”0”
declare -ir PPID=”846”
declare -ir UID=”0”
declare -i numar=”20”
$

Se pot utiliza numere reprezentate în baze de numeraţie diferite, de


la baza 2 la baza 36. Formatul general de reprezentare într-o anumită bază
este:
variabila=baza#numarul_in_acea_baza

Spre exemplu, dacă: nr=2#110, atunci avem numărul 110


reprezentat în baza 2. Se pot declara numere octale (în baza 8) dacă valoarea
numerică a acestora este precedată de un 0 (zero). De exemplu, dacă avem
comanda: declare -i nr=020, atunci variabila nr are valoarea zecimală 16.

Comanda let
Comanda let este o comandă internă bash utilizată pentru a realiza
operaţii aritmetice cu întregi şi a testa expresii numerice. Operatorii care
sunt acceptaţi de comanda let pot fi vizualizaţi cu ajutorul comenzii: help
let.

Numere reale
Shell-ul bash oferă suport doar pentru operaţii cu numere întregi;
dacă avem de făcut calcule cu numere reale, putem folosi utilitarele bc, awk
sau nawk.
Exemple:

$ nr=`echo “scale=2; 12 / 5” | bc`


$ echo $nr
2.40

$ p=`gawk -v x=2.2 -v y=3.3 ‘BEGIN{printf “%.2f\n”,x*y}’`


$ echo $p
7.26

185
Bourne again shell

8.3.3 Parametri poziţionali şi comanda set

Parametrii poziţionali sunt aceeaşi cu cei din Bourne Shell: $0 este


numele script-ului, $1-$9 reprezintă valorile parametrilor poziţionali iar $*
listează toţi parametrii poziţionali. Dacă numărul parametrilor poziţionali
era restrâns la 9 pentru shell-ul Bourne, în bash putem folosi câţi parametri
poziţionali dorim. Pentru valori mai mari decât 9, ei vor fi referiţi astfel:
${10}, ${11}, etc. ”$*” semnifică extinderea la un singur argument, de
genul: “$1 $2 $3”, iar ”$@” are semnificaţia: ”$1” ”$2” ”$3”.
Considerăm următorul exemplu:
#!/bin/bash
#Numele script-ului este test
echo “Numele script-ului este $0”
echo “Primul parametru pozitional este $1”
echo “Al doilea parametru pozitional este $2”
echo “Al 10-lea parametru pozitional este ${10}”

Apelat astfel:

$./test 1 2 3 4 5 6 7 8 9 10 11

vom obţine listing-ul:

Numele script-ului este ./test


Primul parametru pozitional este 1
Al doilea parametru pozitional este 2
Al 10-lea parametru pozitional este 10

Comanda set poate fi folosită pentru resetarea parametrilor


poziţionali. Dacă este apelată fără nici un argument, comanda set va afişa
toate variabilele care au fost definite în acel shell, locale sau exportate. În
momentul apelului comenzii cu unul sau mai multe argumente, parametrii
pozitionali definiţi anterior se pierd (pentru a reveni la valorile iniţiale se
poate utiliza comanda set --).

186
UNIX

Fie exemplul următor:

#!/bin/bash
#Numele script-ului este test2
echo “Numele script-ului este $0”
echo “Parametrii sunt: $*”
echo “Al doilea parametru pozitional este $2”
echo “Numarul parametrilor este $#”
arg_vechi=$*
set ion maria cornel gheorghe stefan
echo “Parametrii sunt acum: $*”
set $(date)
echo “Astazi este $3 $2 $6”
echo “Vechii parametri sunt: $arg_vechi”
set $arg_vechi
echo $1 $2 $3

În urma execuţiei shell-script-ului de mai sus prin apelul: ./test2 1 2


3 se va afişa:

Numele script-ului este ./test2


Parametrii sunt: 1 2 3
Al doilea parametru pozitional este 2
Numarul parametrilor este 3

Parametrii sunt acum: ion maria cornel gheorghe stefan

Astazi este 15 Aug 2004


Vechii parametri sunt: 1 2 3
1 2 3

Variabilele speciale pot fi folosite şi în construcţii speciale:


#!/bin/bash
#Numele script-ului este test3
nume=${1:?”necesita un argument!”}
echo Buna ziua, $1!

Dacă test3 este apelat fără nici un argument, va fi afişat mesajul de


eroare: ./test3: 1: necesita un argument! Dacă facem apelul: ./test3 Razvan,
vom obţine rezultatul: Buna ziua, Razvan!
187
Bourne again shell

8.3.4 Construcţii condiţionale şi controlul fluxului

Construcţiile condiţionale ne permit să testăm anumite condiţii şi


apoi să executăm anumite comenzi în funcţie de rezultatul testărilor.
Comanda if reprezintă cea mai simplă construcţie condiţională utilizată
pentru luarea deciziilor. Ca şi shell-ul Bourne, bash utilizează valoarea lui
exit-status pentru a vedea care este rezultatul unei comenzi (reamintim că în
cazul în care comanda s-a încheiat cu succes sau cu valoarea logică true
exit-status-ul este egal cu zero iar în caz contrar exit-status-ul are o valoare
diferită de zero). Valoarea lui exit-status pentru ultima comandă este $?.
Pentru a evalua starea de adevăr a unei expresii este folosită comanda
internă test, sau se folosesc parantezele pătrate. Considerăm în continuare
câteva exemple de utilizare a comenzii test, a parantezelor pătrate, construcţia
cu paranteze pătrate duble [[ ]] şi cu paranteze duble (( )).

Exemplul 1.
Vom introduce la linia de comanda:

$ nume=barbu
$ grep “$nume” /etc/passwd > /dev/null
$ echo $?
0 #barbu a fost gasit in /etc/passwd

$ test $nume != barbu


$ echo $?
1 #numele nu este diferit de barbu

$ [ $nume = barbu ]
$ echo $?
0 #testul este adevarat de aceasta data

$ [ $nume = [Bb]arbu ]
$ echo $?
1 #comanda test nu permite folosirea metacaracterelor

Pentru a putea utiliza metacaractere în cadrul comenzii test trebuie să


folosim parantezele pătrate duble, ca în exemplul următor:

$ [[ $nume == [Bb]arbu ]]
$ echo $?
0

188
UNIX

Prin utilizarea parantezelor duble (( )) se pot evalua expresii


numerice. Considerăm exemplul următor:

$ x=3; y=5
$ (( x > y ))
$ echo $?
1

Rezultatul afişat este 1 deoarece x nu este mai mare decât y (3<5).

Comanda if
Noul format al comenzii if pentru bash este:

if [[ com_test1 ]]
then
secventa_comenzi1
else
secventa_comenzi2
fi

sau, pentru testări numerice:

if (( com_test1 ))
then
secventa_comenzi1
else
secventa_comenzi2
fi

Observaţie. else este opţional.

Comanda exit
Comanda exit este utilizată pentru a termina shell-script-ul şi a
reveni la linia de comandă. Comenzii exit i se poate da un argument (un
număr între 0 şi 255) pentru a indica faptul că programul s-a încheiat cu
succes sau nu. Asemănător cu exit-status-ul, valoarea 0 înseamnă încheierea
cu succes a programului. Argumentul pe care îl dăm comenzii exit se află
stocat în variabila $?.

189
Bourne again shell

Comanda case
Comanda case este utilizată pentru construcţii condiţionale multiple.
Formatul acesteia este acelaşi cu formatul shell-ului standard Bourne:

case variabila in
sablon_1)
comenzi
;;
sablon_2)
comenzi
;;

*)
comenzi
;;
esac

Dacă nici una dintre valorile sablon_1, sablon_2, etc. nu corespund


valorii variabilei respective, se vor executa în mod implicit comenzile ce
urmează după construcţia specială *).

8.3.5 Comenzi de ciclare

Comenzile utilizate pentru ciclare sunt: for, while, until, select.


Dintre acestea, primele trei ne sunt familiare din shell-ul Bourne. În shell-ul
bash apare un nou mecanism de ciclare, denumit select, utilizat cu
principalul scop de a crea meniuri.
Comanda select afişează un meniu cu opţiuni numerotate 1, 2, 3 etc.
Afişarea se face în fişierul standard error (pe ecran, implicit). Pe ecran,
cererea de a introduce una dintre opţiuni se face prin afişarea prompter-ului
PS3 (al treilea prompter), care implicit are valoarea #?. Dacă dorim să
afişăm un mesaj, va trebui să modificăm doar valoarea lui PS3. Dar să
vedem cum funcţionează comanda select: după afişarea meniului şi a
prompter-ului PS3, se aşteaptă pentru introducerea unui număr din lista
afişată. Input-ul va fi stocat în variabila specială REPLY.
De regulă, comanda select se foloseşte împreună cu comanda case
pentru a crea un meniu ce permite utilizatorului să facă o selecţie dintr-un
meniu şi pe baza acelei selecţii să execute anumite comenzi. De asemenea,
se pot utiliza variabilele predefinite LINES şi COLUMNS pentru a schimba
modul de afişare pe ecran a opţiunilor (aceste variabile sunt definite

190
UNIX

începând cu versiunea 2.0 bash). Pentru a întrerupe execuţia comenzii select


se va folosi fie break (pentru ieşirea din ciclul select), fie exit pentru a ieşi
din program. Formatul general al instrucţiunii select este:

select variabila in lista


do
comenzi
done

Prezentăm în continuare câteva exemple de utilizare a comenzii


select.

Exemplul 1.

#!/bin/bash
# Nume shell-script: meniu_select
PS3=”Selectati optiunea dorita:”

select prog in ‘uname -n’ date cal who exit

do
$prog
done

Execuţia programului va duce la afişarea unui meniu:

1) uname -n
2) date
3) cal
4) who
5) exit
Selectati optiunea dorita:

În funcţie de opţiunea selectată, se va executa comanda respectivă.


Ciclul select va rula fie până la introducerea opţiunii 5 (exit va determina
ieşirea din program), fie până la introducerea combinaţiei Ctrl+C.

191
Bourne again shell

Exemplul 2.

#!/bin/bash
# Nume shell-script: culori
PS3=”Alegeti una dintre culori sau exit:”

select alegere in albastru galben verde exit

do
case alegere in
albastru)
echo “Albastrul este culoarea cerului!”
break;;
galben)
echo “Galbenul este o culoare calda!”
break;;
verde)
echo “Verde este padurea!”
break;;
*)
echo “$REPLY nu este o optiune valida!”
echo “Incercati din nou.”
;;
esac
done

Iniţial, se va afişa meniul:

1) albastru
2) galben
3) verde
4) exit
Alegeti una dintre culori sau exit:

În funcţie de opţiunea aleasă se va afişa mesajul corespunzător. Dacă


se introduce valoarea 4 se va ieşi din program şi orice altă valoare introdusă
va afişa mesajul în care se precizează că nu este o opţiune validă şi se va
repeta introducerea opţiunii.

Rularea instrucţiunilor de ciclare în background


Instrucţiunile de ciclare pot fi rulate în background, astfel încât
programul poate continua fără să aştepte terminarea instrucţiunii de ciclare.

192
UNIX

În exemplul următor se trimite un email mai multor utilizatori preluat din


fişierul scrisoare:

#!/bin/bash
for nume in radu andrei andra serban gabi
do
mail $nume < scrisoare
done &

Semnul & (ampersand) de la sfârşitul instrucţiunii for determină


execuţia ciclului for în background. Programul îşi va continua execuţia până
la terminarea ciclului for.

Separatorul IFS
Separatorul intern al shell-ului IFS (Internal Field Separator) are
valoare de spaţiu, tab sau caracter de linie nouă (newline). El este folosit
drept caracter separator în cadrul comenzilor pentru interpretarea semantică
a cuvintelor cheie, precum: for, do, done, etc. Acest separator poate fi
modificat de către utilizator dacă se doreşte utilizarea altui separator într-o
listă. Înainte de a modifica valoarea separatorului, este bine să memorăm
vechea valoare a lui IFS în altă variabilă, pentru a putea reface starea iniţială
a separatorului. Prezentăm în continuare un exemplu de modificare a
separatorului IFS.

#!/bin/bash
# Exemplu pentru IFS
nume=Radu:Andrei:Andra:Serban:Gabi
ifs_vechi=”$IFS”
IFS=”:”
for persoana in $nume
do
echo Salut $persoana
done

IFS=”$ifs_vechi”
set Cristi Cristina Paul
for prenume in $*
do
echo Buna ziua $prenume
done

193
Bourne again shell

La început, variabila nume are valoarea şirului de caractere


Radu:Andrei:Andra:Serban:Gabi, numele fiind separate de câte un caracter
„:”. Vechea valoare a lui IFS este memorată în variabila ifs_vechi. Deoarece
valoarea lui IFS este un caracter whitespace, trebuie încadrată între
ghilimele. Apoi lui IFS i se atribuie o nouă valoare, semnul „:” care va fi de
acum utilizat pe post de separator. Ca urmare a execuţiei shell-script-ului
anterior se va afişa:

Salut Radu
Salut Andrei
Salut Andra
Salut Serban
Salut Gabi
Buna ziua Cristi
Buna ziua Cristina
Buna ziua Paul

8.3.6 Funcţii

Funcţiile au fost introduse în shell-ul Bourne începând cu versiunea


AT&T UNIX SystemVR2 (SVR2) şi le-au fost adăugate o serie de
îmbunătăţiri în shell-ul Bourne Again. Funcţiile reprezintă asocierea unui
nume pentru o comandă sau un grup de comenzi, fiind folosite pentru
modularizarea programelor, făcându-le astfel mai eficiente. Funcţiile sunt
executate în contextul shell-ului curent, astfel că nu se creează un nou
proces copil ca în cazul rulării unui program executabil precum cat.
Funcţiile pot fi scrise în fişiere separate pentru a fi încărcate în memorie din
shell-script atunci când trebuie folosite. În continuare sunt prezentate
regulile de scriere a funcţiilor în Bourne Again Shell:
1. O funcţie trebuie definită înainte de a fi utilizată.
2. Funcţia rulează în mediul de lucru curent, partajând variabilele din
shell-script-ul ce o invocă şi oferă posibilitatea de transmitere de argumente
prin atribuirea acestora ca parametri poziţionali. Variabilele locale pot fi
create în cadrul unei funcţii prin utilizarea funcţiei local.
3. Shell-ul determină dacă se foloseşte un alias, o funcţie, o comandă
internă sau un program executabil aflat pe hard-disc. Ordinea de căutare
este: alias, funcţie, comandă internă, program executabil.
4. În momentul în care se utilizează comanda exit în cadrul unei
funcţii, se produce ieşirea din shell-script-ul ce apelează funcţia. Dacă se

194
UNIX

iese din funcţie, întoarcerea în shell-script se face pe linia următoare


apelului funcţiei.
5. Comanda return în cadrul unei funcţii determină returnarea valorii
exit-status a ultimei comenzi executate în cadrul funcţiei sau valoarea
argumentului specificat.
6. Funcţiile pot fi exportate în sub-shell-uri folosind comanda internă
export -f.
7. Pentru a lista funcţiile şi definiţiile acestora, se foloseşte comanda
declare -f. Începând cu versiunea 2.x. bash, pentru a lista doar numele
funcţiilor se foloseşte comanda declare -F.
8. Dacă funcţiile sunt stocate într-un fişier separat, acestea pot fi
încărcate în mediul curent prin comanda source sau comanda dot (.).
9. Se permite declarea funcţiilor recursive (ce se auto-apelează). Nu
există o limită maximă impusă pentru numărul de apeluri recursive.
10. Variabilele, ca şi valorile trap sunt globale în cadrul funcţiilor. Ele
sunt partajate atât de către shell-script cât şi de funcţiile invocate de acel
shell-script. Dacă o valoare trap este definită în cadrul unei funcţii, ea este,
de asemenea, partajată de shell-script.

Alte comenzi legate de funcţii.


Pentru a reseta o funcţie se foloseşte comanda unset. Formatul
general al acestei comenzi este:

unset -f nume_functie

Pentru a exporta o funcţie într-un sub-shell se foloseşte comanda


export. Formatul general al acestei comenzi este:

export -f nume_functie

În cadrul unei funcţii, argumentele pot fi transmise funcţiilor prin


intermediul parametrilor poziţionali. Parametrii poziţionali sunt privaţi în
cadrul funcţiilor, astfel încât argumentele unei funcţii nu vor afecta
parametrii poziţionali utilizaţi în afara acesteia. Pentru a crea variabile
locale (care nu vor mai fi valabile la ieşirea din funcţie) pentru o funcţie
anume putem folosi comanda internă local.
Comanda return poate fi utilizată pentru a termina execuţia funcţiei
şi a preda controlul script-ului apelant. Valoarea returnată de o funcţie este
egală cu valoarea exit-status returnată de ultima comandă executată
195
Bourne again shell

în cadrul funcţiei, cu excepţia cazului în care se specifică un anumit


argument prin intermediul comenzii return. În momentul în care se specifică
o valoare prin comanda return, această valoare este stocată în variabila ? şi
poate lua valori întregi cuprinse între 0 şi 255. Datorită acestei limitări, se
poate utiliza substituirea comenzii pentru a captura valoarea returnată de o
funcţie. În acest sens, se poate scrie toată funcţia între paranteze precedate
de semnul $ sau între apostrofurile inverse (``) pentru a captura şi atribui
valoarea returnată de către funcţie unei variabile, ca şi în cazul obţinerii
rezultatului unei comenzi UNIX.
Prezentăm în continuare câteva exemple de utilizare a funcţiilor.

Exemplul 1.

#!/bin/bash
# Nume shell-script: verific_functie

function UTI { echo “Eroare: $*” 2>&1; exit 1; }

if (( $# != 2 ))
then
UTI “$0: necesita doua argumente”
fi
if [[ ! ( -r $1 && -w $1 ) ]]
then
UTI “$1: fara drepturi de citire si scriere”
fi
echo Argumentele sunt: $*
...# comenzi

Explicaţii.
În exemplul anterior se defineşte o funcţie UTI ce este utilizată
pentru a afişa un mesaj de eroare pe ecran (fişierul standard de eroare).
Argumentele funcţiei constau în orice şir de caractere trimise odată cu
apelul funcţiei. Argumentele sunt stocate în $*, variabila specială ce
stochează toţi parametrii poziţionali. În cadrul unei funcţii, parametrii
poziţionali sunt consideraţi locali şi nu au efect asupra parametrilor utilizaţi
în afara funcţiei. În cadrul script-ului se verifică dacă numărul parametrilor
poziţionali este 2 şi în caz contrar se afişează mesajul de eroare
corespunzător. În momentul apelării funcţiei UTI, şirul ”$0: necesita doua
argumente” este transmis funcţiei şi memorat în variabila $* iar comanda
echo va afişa mesajul de eroare şi apoi se va returna valoarea de ieşire 1,
ceea ce indică faptul că ceva nu a fost în regulă. În continuarea programului,
196
UNIX

se verifică dacă primul argument este un fişier care poate fi citit şi


modificat, iar funcţia UTI va fi apelată cu argumentul „$1: fara drepturi de
citire si scriere”. Argumentele ce provin de la linia de comandă sunt stocate
din nou în $*, fără a avea efect pentru valoarea $* din cadrul funcţiei.

Exemplul 2.

#!/bin/bash
# Nume shell-script: incrementare

INC () {
local suma;
let “suma=$1 + 1”
return $suma
}
echo -n “Suma este:”
INC 5
echo $?
echo $suma # variabila suma nu este cunoscuta in
#afara functiei

Explicaţii.
În exemplul anterior se defineşte o funcţie INC. În cadrul acestei
funcţii se declară variabila locală suma, care nu este cunoscută în afara
funcţiei. În momentul apelului funcţiei, valoarea primului argument, $1 va fi
incrementată cu 1 iar rezultatul va fi atribuit variabilei suma. Comanda
internă return va atribui variabilei $? valoarea din variabila suma, apoi şirul
este afişat pe ecran. Funcţia INC este apelată cu argumentul 5, iar
exit-status-ul ei va fi stocat în variabila $?. Pentru ultima linie din program
nu se va afişa nimic, deoarece variabila suma a fost declarată doar în
interiorul funcţiei (cu ajutorul comenzii interne local) şi valoarea acestei
variabile nu este cunoscută în afara funcţiei.

197
Bourne again shell

Exemplul 3.

#!/bin/bash
# Nume shell-script: cub

function CUB {
local rez;
let “rez=$1 * $1 * $1”
echo “Numarul ce va fi ridicat la cub este $1”
echo “Rezultatul este $rez”
}
echo -n “Introduceti numarul pentru ridicare la cub:”
read numar
rezultat=$(CUB $numar)
echo -n “$rezultat”

Explicaţii.
În exemplul anterior se defineşte o funcţie CUB. În cadrul acestei
funcţii se declară variabila locală rez, care va stoca rezultatul. În cadrul
script-ului se citeşte valoarea care va fi ridicată la cub în variabila numar,
apoi se atribuie variabilei rezultat valoarea întoarsă de funcţie prin
intermediul substituirii comenzii (construcţia cu numele funcţiei între
paranteze precedate de semnul $). Prin comanda echo de pe ultima linie a
shell-script-ului se afişează rezultatul.

Observaţie. Ca şi în Bourne Shell, funcţiile se încarcă în memorie cu


ajutorul comenzii dot (.). În Bourne Again Shell există însă şi comanda
source, care se apelează astfel:

$ source fisier_functii

unde fisier_functii este fişierul ce conţine funcţiile ce vor fi utilizate.

198
Bibliografie

1 Anderson, R. UNIX File system Administration, Sams


Publishing, 2002
2 Bach, M.J. The Design of the UNIX Operating
System, Prentice Hall, Englewood Cliffs,
N.J., 1986
3 Brăescu, C. L., Internet pentru începători, Bucureşti,
Dudaş, L. Editura TIMS, 1995
4 Burtch, K.O. Linux Files, Users and Shell
Customization with Bash, Sams,
Developer’s Library, 2004
5 Compaq Tru64 UNIX Documentation Overview,
Compaq Computer Corporation,
Houston, Texas, USA, 1999-1
6 Compaq Tru64 UNIX Security, Compaq
Computer Corporation, Houston, Texas,
USA, 1999-2
7 Danesh, A. Mastering Linux, sec. Edition, USA,
Michael, J. Sybex, 2001
8 David, N. Network Security, prezentare Cisco
Seminar Series, 1998
9 Dodescu Gh., Sisteme de operare MS-DOS şi UNIX,
Vasilescu, A. Bucureşti, Editura Viaţa Românească,
1994
10 Dodescu, Gh., Sisteme de calcul şi operare, Bucureşti,
Năstase, F. 1995/1
11 Dodescu, Gh., Sisteme de calcul şi operare, Bucureşti,
Năstase, F Editura Aldo, 1995

12 Done, G. Sun Enterprise Cluster 2.2, articol PC


Report, noiembrie 1999
13 Hahn, H., The Internet Complete Reference, 1993
Stout, R.

199
UNIX

14 Hall, E. A., Internet Core Protocols: the definitive


O'Reilly, & guide, Inc., 2000
Assosiates
15 Kurose, J. Computer Networking, A Top-Down
Keith, R., Approach Featuring the Internet, 2001
Wesley, A.
16 Lammle, T. CCNA Study Guide, Second Edition,
Sybex, 2000
17 McMullen, J. Advanced UNIX user’s handbook,
Prentice Hall PTR, 2000
18 Myers, D., Fundamentals of UNIX Companion
Lorenz, J. Guide, Cisco Systems Inc., 2002

19 Năstase, F. Arhitectura reţelelor de calculatoare,


Bucureşti, Editura Economică, 1999
20 Pănoiu, Al. Compaq Tru64 UNIX, articol PC Report,
iunie 1999

21 Pitiş, A. GNU/Linux: o alegere morală?, articol


PC Report, noiembrie 1999

22 Poniatowski, M. UNIX user’s handbook, sec. Edition,


Prentice Hall PTR, 2002
23 Quigley, E. UNIX Shells by Example, third edition,
Prentice Hall PTR, 2002
24 Rosch, L. W. Puneţi Linux-ul la treabă, articol PC
Magazine, februarie 2000
25 Roşca, I. G., Intranet, Bucureşti, Editura ASE, 1999
Ţăpuş, N.,
Cristea, V.,
Atanasiu, I.,
Costinescu B.,
Năstase, F.,
Stanciu, C.,
Paiu, O.,
Godza, G.
200
Bibliografie

26 Sage, G. R. UNIX pentru profesionişti, Timişoara,


Editura de Vest, 1992
27 Stallings, W. Operating Systems, fourth edition,
Prentice Hall PTR, 2001
28 Stevens, W. R. UNIX Network Programming, Prentice
Hall, Englewood Cliffs, N.J., 1990
29 Tanenbaum, A. Computer Networks, 3rd ed., Prentice-
Hall, 1996
30 Tanenbaum, A. Reţele de calculatoare, Târgu Mureş,
Editura Agora, 1998
31 Taylor, D. UNIX Disk Usage, Sams, informIT.com,
Ianuarie 2003
32 Toxen, B. Linux Security: The Seven Most Deadly
Sins, Prentice Hall PTR, 2003
33 Vasilescu, A. Reţele de calculatoare, Bucureşti,
Editura Inforec, ASE 1999
34 Wrightson, K., Mastering UNIX, USA, Sybex, 2001
Merlino, J.
35 Zota, R. D. UNIX – interacţiunea dintre procese şi
kernel, lucrare la Simpozionul Naţional
de Informatică Craiova, 1998
36 Zota, R. D. Sisteme de operare pentru reţele de
calculatoare, Bucureşti, Editura
Economică, 2002
37 Zota, R. D. Sistemul de operare UNIX - Utilizare şi
programare shell, Bucureşti, Editura
ASE, 2003

201