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 UNIX A/UX AIX HP-UX Linux NextStep OSF/1 şi Ultrix SCO OpenServer Solaris UNIXWare Platforma hardware Macintosh Staţii şi mainframe-uri IBM, RS/6000 Staţii HP RISC Intel x86 Intel 486 sau Pentium, Next Staţii DEC VAX şi Alpha Intel 486 sau Pentium Staţii Sun Sparc şi Intel x86 Intel 486 sau Pentium Vânzător Apple Computer IBM Hewlett-Packard Corporation Shareware Next Computer Digital Equipment Corporation Santa Cruz Operation SunSoft 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 softwareului 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.
$ man -s nr_sectiune nume

Oferă informaţii cu privire la o 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.
$ man -k cuvant_cheie

Oferă informaţii cu privire la 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:
$ whatis comanda

Afişează linia de început din cadrul 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 Tasta RETURN Tasta b Tasta f Tasta q /sir_caractere Tasta n Tasta h

Determină defilarea ecran cu ecran Determină defilarea unei singure linii de ecran Înapoi cu un ecran (b - back) Înainte un ecran (f - forward) Se încheie listarea şi comanda man (q - quit) Se caută şirul de caractere specificat Se caută următoarea apariţie a şirului de caractere (n - next) 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 http://www.FreeBSD.org/cgi/man.cgi http://docs.hp.com/index.html http://docs.sun.com/ http://www.ibm.com/servers/aix/ http://support.sgi.com/search/ http://doc.sco.com/ Varianta de UNIX BSD HPUX 10 & 11 SunOS, Solaris IBM AIX SGI IRIX/Linux 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
2.1

SISTEMUL DE FIŞIERE UNIX ŞI COMENZI

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 "root" Reprezintă nivelul cel mai de sus din sistemul de 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 Super-blocul • • • • Tabela de inoduri • • • • • • • • • • Aici se află procedurile de boot 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 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 Blocuri de date Fişiere obişnuite - conţinut Fişiere director – nume de fişiere şi numerele inodurilor

Blocurile de stocare

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: Comenzi UNIX Director pentru dispozitive speciale Programe şi fişiere de date suplimentare Directorul bibliotecii de programe C 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ă /bin /dev /etc /lib /mnt

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 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 Principalele tipuri de fişiere existente pe un sistem UNIX sunt:

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 /dev/cua /dev/dsk /dev/fd /dev/kmem /dev/log /dev/mem /dev/null /dev/pts /dev/rdsk /dev/rmt /dev/swap /dev/tty /dev/zero Descriere Director pentru dispozitive seriale Director pentru dispozitive de tip bloc (hard-discuri, CD-ROM-uri, etc.) Director pentru unităţi floppy Director pentru memoria virtuală kernel Director socket către login-ul sistem Dispozitiv pentru memoria fizică Dispozitivul „null” Pseudo-terminale Director pentru echipamente device de tip caracter Director pentru medii de stocare movibile – bandă magnetică Spaţiul de swap Director pentru linii terminal 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 dea 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 -r--r--r-1 root drwxr-xr-x 2 root -rwxr-xr-x 2 root -rwxr-xr-x 2 root -rwxr-xr-x 1 bin -rwxr-x--x 1 root -rwxr-x--x 1 root -rwxr-xr-x 2 root -rwxr-xr-x 2 root -rwxr-xr-x 1 root -rwxr-xr-x 1 root drwxr-xr-x 2 root -rwxr-x--x 1 root sys sys sys sys sys bin sys sys sys sys sys sys sys sys 60676 Aug 22 1994 Lib 60676 Aug 22 1994 README 60676 Aug 22 1994 Source 60676 Aug 22 1994 gzexe 60676 Aug 22 1994 gzip 242436 Feb 20 16:07 httpd 599604 Sep 22 1995 kermit 171195 Jan 22 12:15 memhog 5599 Jan 22 12:15 nlsym 553836 Feb 20 16:40 perl 553836 Feb 20 16:40 perl5.003 13855 Feb 20 16:40 perlbug 8984 Feb 20 16:40 perldoc 60676 Aug 22 1994 src 108781 Jan 22 12:15 u486mon

-rwsr-xr-x 1 uucp uucp

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 d r w x r w x r w x r w x r - x r w x r w r - - - - - r w x r - r - - - - - -

Cele 10 coloane care reprezintă drepturile de acces la fişiere sunt: Să analizăm în continuare semnificaţia acestor coloane:
Coloana 1 d d r r r r Coloana 2-4 w x w x w x x r r r Coloana 5-7 w x w Coloana 8-10 r w x r r -

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 d b c l M P S b) Descriere Fişier simplu ("ordinary file") Director Fişier bloc ("block special") Fişier caracter ("character special") Fişier legătură ("link") Fişier de memorie partajată ("shared memory") Fişier pipe ("named pipe") 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 -r--r--r-drwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwsr-xr-x -rwxr-x--x -rwxr-x--x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x -rwxr-xr-x drwxr-xr-x -rwxr-x--x

2 1 2 2 2 1 1 1 1 2 2 1 1 2 1

root root root root root bin uucp root root root root root root root root

sys sys sys sys sys bin uucp sys sys sys sys sys sys sys sys

60676 Aug 22 1994 Lib 60676 Aug 22 1994 README 60676 Aug 22 1994 Source 60676 Aug 22 1994 gzexe 60676 Aug 22 1994 gzip 242436 Feb 20 16:07 httpd 599604 Sep 22 1995 kermit 171195 Jan 22 12:15 memhog 5599 Jan 22 12:15 nlsym 553836 Feb 20 16:40 perl 553836 Feb 20 16:40 perl5.003 13855 Feb 20 16:40 perlbug 8984 Feb 20 16:40 perldoc 60676 Aug 22 1994 src 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 Reprezintă orice caracter sau secvenţă de caractere Identifică un singur caracter Permite scrierea mai multor comenzi pe aceeaşi linie Identifică o mulţime sau un domeniu de caractere pentru o singură poziţie Redirectează ieşirea unei comenzi către un fişier în loc de ecran (stdout fişierul standard de ieşire). Redirectează intrarea unei comenzi dintr-un fişier în loc de tastatură (stdin - fişierul standard de intrare) Redirectează eroarea unei comenzi către un fişier în locul ecranului Adaugă ieşirea unei comenzi la un fişier existent (concatenare) * ? comanda;comanda [domeniu] comanda > fisier Formatul comenzii

<

comanda < fisier

2> >>

comanda 2> fisier comanda >> fisier

45

Sistemul de fişiere UNIX şi comenzi Metacaracterul | (semnul pipe) $ % ~ ! Descriere Preia ieşierea unei comenzi şi o pasează ca intrare comenzii următoare Indicatorul prompter-ului standard pentru shell-ul Bourne şi Korn Indicatorul prompter-ului standard pentru shell-ul C Indică directorul home Re-execuţia comenzii Formatul comenzii comanda | comanda Nu se aplică Nu se aplică ~ !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
3.1

ADMINISTRAREA FIŞIERELOR ŞI DIRECTOARELOR

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 dintrunul 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 $ rm stud1 stud2 stud3 $ rm -r TEMP

Se şterge fişierul student.txt Se şterg fişierele stud1, stud2 şi stud3 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:
$ mv student.txt student.doc

Se redenumeşte fişierul student.txt cu noul nume student.doc

62

Administrarea fişierelor şi directoarelor

$ mv student temp

Se redenumeşte fişierul student în temp (de remarcat este faptul că, dacă temp este un director, fişierul student va fi mutat în acel director). Se mută fişierul student în directorul /home/serban/temp

$ mv student /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 /dev/sda5 /dev/sda1 /dev/sda3 none /dev/sdb1 /dev/sdb2 1k-blocks 380791 49558 16033712 256436 17245524 253871 Used 108116 7797 62616 0 1290460 88384 Available 253015 39202 15156608 256436 15079036 152380 Use% 30% 17% 1% 0% 8% 37% Mounted on / /boot /home /dev/shm /usr /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 /dev/sda5 /dev/sda1 /dev/sda3 none /dev/sdb1 /dev/sdb2 Size 372M 48M 21G 250M 22G 248M Used 106M 7.7M 62M 0 1.3G 87M Avail 247M 38M 20G 250M 20G 148M Use% 30% 17% 1% 0% 8% 37% Mounted on / /boot /home /dev/shm /usr /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 / /boot /proc /dev/fd /etc/mnttab /var/run /tmp /export/home (/dev/dsk/c0d0s0 ): 827600 blocks 276355 files total: 2539116 blocks 320128 files (/dev/dsk/c0d0p0:boot): 17584 blocks -1 files total: 20969 blocks -1 files (/proc ): 0 blocks 1888 files total: 0 blocks 1932 files (fd ): 0 blocks 0 files total: 0 blocks 258 files (mnttab ): 0 blocks 0 files total: 0 blocks 1 files (swap ): 1180000 blocks 21263 files total: 1180008 blocks 21279 files (swap ): 1180000 blocks 21263 files total: 1180024 blocks 21279 files (/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 16 412 36 32 196 48 16 1232 4 8 1848 3092 160 136 10464 76 52 2792 24 2872 2880 554 184 14 140 360 196 86 20 1110 6848 190 13974 28484 ./.kde/Autostart ./.kde ./bin ./CraigsList ./DEMO/Src ./DEMO ./elance ./Exchange ./Gator/Lists ./Gator/Old-Stuff/Adverts ./Gator/Old-Stuff ./Gator/Snapshots ./Gator ./IBM/i ./IBM/images ./IBM ./CBO_MAIL ./Lynx/WWW/Library/vms ./Lynx/WWW/Library/Implementation ./Lynx/WWW/Library/djgpp ./Lynx/WWW/Library ./Lynx/WWW ./Lynx/docs ./Lynx/intl ./Lynx/lib ./Lynx/lynx_help/keystrokes ./Lynx/lynx_help ./Lynx/po ./Lynx/samples ./Lynx/scripts ./Lynx/src/chrtrans ./Lynx/src ./Lynx/test ./Lynx .

70

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

atime [+|-]n

perm mod

size [+|-]n[c]

Prezentăm în continuare câteva exemple:
$ find / -name ls -print

$ find / -name seminar_unix\ -type f -print $ find /usr -name hello -type\ f -print

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

72

Administrarea fişierelor şi directoarelor

$ find /usr -name “sem*”\ -type f -print $ find ~ -name “*gif”\ -type f -print

Se caută din directorul usr toate fişierele al căror nume începe cu sem. Se caută plecând din directorul 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) * (asterisc) Acţionează pe post de orice caracter şi poate fi utilizat de mai multe ori Este folosit pentru zero, unul sau mai multe caractere Este folosit pentru a specifica începutul liniei (se 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 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 următorul caracter special după \ în mod normal Verifică apariţia unei secvenţe de caractere din domeniul specificat

^ (caret) $ (dolar) \ (backslash) [] (paranteze pătrate)

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 (+|-)n

Permite o sortare numerică Începe (+) sau se termină (-) cu câmpul ce urmează după al n-lea separator. Separatorul implicit este spaţiul Inversează ordinea de sortare Utilizat pentru a ignora diferenţa între litere mari şi litere mici În acest caz se utilizează ordinea de dicţionar; sunt comparate doar literele, cifrele şi caracterele white spaces iar toate celelalte simboluri sunt ignorate Sortează primele trei caractere ale câmpului drept prescurtări ale numelor lunilor anului Rezultatul comenzii va fi stocat în fişierul specificat de nume_fisier, în loc să fie afişat pe ecran

-r -f

-d +nM -o nume_fisier

Î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 t x F V

Creează o nouă arhivă jar Listează conţinutul fişierului jar Extrage fişierele specificate din arhiva jar Specifică fişierul jar magnetică (/dev/rmt/x) (/tmp/fisier.jar) sau banda

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
Opţiunea -a (--ascii) Tabelul 3.26 Semnificaţie Foloseşte modul text ASCII Caracterele sfârşit de linie (end-ofline) 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. Scrie rezultatul produs către standard output şi lasă fişierul de intrare nemodificat. Decomprimă fişierul specificat 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. Afişează informaţii de ajutor Afişează informaţii despre fiecare fişier comprimat. Afişează informaţii despre licenţa gzip Nu salvează implicit folosind numele fişierului iniţial 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. Suprimă toate mesajele de avertisment Acţionează pe structura directorului recursiv (inclusiv subdirectoarele) Modifică extensia implicită .gz în extensia specificată în sufix. Face un test de integritate a fişierului comprimat Afişează informaţii adiţionale pentru fiecare fişier în parte, cum ar fi numele şi procentul de reducere a dimensiunii

-c (--stdout) -d (--decompress) -f (--force)

-h (--help) -l (--list) -L -n (--no-name) -N (--name)

-q (--quiet) -r (--recursive) -s sufix -t (--test) -v (--verbose)

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

1. Servicii de reţea

4

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 Connected to infocib. AIX version 5 infocib login: stud password: Welcome to infocib – rs6000 aix 5L $ Comanda de iniţializare a unei comunicaţii telnet cu serverul infocib Mesajul primit ca urmare a stabilirii conexiunii pe serverul infocib Login cu nume de utilizator stud Se introduce parola 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 Connected to infocib. Infocib FTP server (version 5) ready Introducerea comenzii ftp Mesajul de stabilire a conexiunii cu serverul Se cere introducere numelui de login se introduce numele de utilizator stud Se afişează un mesaj prin care se specifică faptul că utilizatorul stud trebuie să se autentifice prin introducerea parolei Se introduce parola Mesajul de întâmpinare de pe server Intrăm în subdirectorul tmp Lansăm comanda get pentru a copia fişierul test.file Transferul fişierului a fost făcut cu succes. Închiderea conexiunii ftp. Apariţia prompter-ului de pe server.

Name: stud

Password required for stud.

Password: User stud logged in. Remote system type is UNIX. Using binary mode to transfer files. ftp>cd tmp CWD command successful ftp>get test.file PORT command successful Opening BINARY mode data connection for test.file Transfer complete. 3305 bytes received în 0.03 seconds ftp> bye Goodbye. $

89

Sertvicii de reţea

Prezentăm în continuare o listă cu cele mai utilizate comenzi ftp:
Comanda ascii Explicaţii 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ă. 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. Modifică directorul curent de lucru pe calculatorul de la distanţă.

binary

cd

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. Comanda este utilizată pentru a copia un fişier de pe calculatorul de la distanţă pe calculatorul local. Modifică directorul curent pe calculatorul local. Listează pe ecran conţinutul directorului curent de pe calculatorul de la distanţă. Comanda este utilizată pentru copierea mai multor fişiere de pe calculatorul de la distanţă. Cu ajutorul comenzii put se copiază fişierul specificat de pe calculatorul local pe calculatorul de la distanţă. Cu această comandă se copiază mai multe fişiere de pe calculatorul local pe calculatorul de la distanţă. Se închide conexiunea ftp cu calculatorul de la distanţă.

get

lcd ls

mget

put

mput

quit/bye

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

time=8. time=9. time=8. time=9. time=9. time=8. time=8. time=8. loss

ms ms ms ms ms ms ms ms

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 127.0.0.1 4136 10.1.1.10 lan0 10.1.1.110 lan1 10.1.1.0 lan0 10.1.1.0 lan1 127.0.0.0 lop0 default 1300 #

Gateway Flags Refs 127.0.0.1 10.1.1.10 4136 10.1.1.110 4136 10.1.1.110 1300 10.1.1.10 1300 127.0.0.1 4136 10.1.1.1 UG

Use UH UH UH U U U 0

Interface Pmtu 0 133563 lop0 0 0 2 2 0 0 356 0 2 0 0 lan1

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 100000 100000 100024 100024 100021 100005 100005 vers 2 2 1 1 1 1 1 proto tcp udp udp tcp udp udp tcp port 111 111 777 779 1024 976 978 service portmapper portmapper status status nlockmgr mountd 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=/ /dev/cdrom /dev/fd0 none none /dev/hda4 / /mnt/cdrom /mnt/floppy /proc /dev/pts swap ext2 defaults iso9660 noauto,owner,ro auto noauto,owner proc defaults devpts gid=5,mode=620 swap defaults 1 0 0 0 0 0 1 0 0 0 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 pass

punct_de_montare tip_director optiuni dum

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=/ /dev/cdrom /dev/fd0 none none /dev/hda4 /dev/hda1 /dev/hda5 0 0

/ /mnt/cdrom /mnt/floppy /proc /dev/pts swap /mnt/c /mnt/d

ext2 iso9660 auto proc devpts swap

defaults 1 noauto,owner,ro 0 noauto,owner 0 defaults 0 gid=5,mode=620 0 defaults 0 auto defaults auto defaults

1 0 0 0 0 0 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 NetworkProperties. 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 linii:

trebuie adăugate următoarele

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
5.1

Editoare de text

1. Editoare de text 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 UNIXului, 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 j (săgeată în jos) k (săgeată în sus) h (săgeată stânga) l (săgeată dreapta) Tasta <SPACE> w b $ 0 sau ^ Tasta <RETURN> Semnificaţie Deplasare o linie în jos Deplasare o linie în sus Deplasare cu un caracter la stânga Deplasare cu un caracter la dreapta Deplasare la dreapta cu un caracter Deplasare la dreapta cu un cuvânt Deplasare la stânga cu un cuvânt Deplasare la sfârşitul liniei Deplasare la începutul liniei 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 x dw 5dw dd 2dd 3x Semnificaţie Se şterge caracterul din dreptul cursorului Se şterge cuvântul (sau partea din cuvânt) situat la dreapta cursorului Se şterg 5 cuvinte la dreapta Se şterge întraga linie pe care este poziţionat cursorul Se şterg 2 linii începând cu linia curentă 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 cw Semnificaţie 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> Se modifică 5 cuvinte Se înlocuieşte caracterul pe care este poziţionat cursorul cu alt caracter Are ca efect anularea ultimei comenzi Şterge, apoi alipeşte (paste) Copiază, apoi alipeşte Copiază o linie Alipeşte linia copiată sau ştearsă sub linia curentă Alipeşte linia copiată sau ştearsă deasupra liniei curente

5cw r u dd, apoi p yy, apoi p yy p P

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

6
6.1 6.1

SHELL-uri UNIX

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 6.5.1

Iniţializarea sistemului şi programul de login 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 shellurile 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ă 000 001 010 011 100 101 110 111 Valoare zecimală 0 1 2 3 4 5 6 7 Drepturi de acces ----x -w-wx r-r-x rwrwx

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
7.1

BOURNE SHELL

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 4 drwxrwxrwx 2 -rwxrwxrwx 1 -rwxrwxrwx 2 -rwxrwxrwx 1 1 1 1 1 root root 2048 Feb15 18:00 . root root 2048 Feb15 18:10 .. razvan cib 1022 Dec15 17:45 .profile razvan cib 102 Feb16 17:45 stud.dat 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 test test [ -r [ -w -d examen.dat; echo $? -x examen.dat; echo $? -s examen.dat; echo $? examen.dat ] ; echo $? 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. b. c. d. e. [ [ [ [ [ $sir1 ] ; echo $? -n $sir3 ] ; echo $? $sir1=$sir4 ] ; echo $? "$sir4"="$sir3" ] ; echo $? -z $sir4 ] ; echo $?

2. Care dintre comenzile următoare vor avea rezultat un exit status egal cu zero?

136

Bourne shell

a. b. c. d. e.

[ [ [ [ [

"$sir1"!="$sir2" ] ; echo $? -z "$sir3" ] ; echo $? -n "$sir4" ] ; echo $? "$sir1"="$sir3" ] ; echo $? "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. b. c. d. e. [ [ [ [ [ "$int1" "$int2" "$int4" "$int3" "$int4" -gt -lt -le -eq -ne "int2" ] ; echo $? "$int3" ] ; echo $? "$int1" ] ; echo $? "$int4" ] ; echo $? "$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 7.2.1

Gramatica Shell 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 7.3.1 Instrucţiuni de selecţie 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 7.4.1

Instrucţiuni iterative 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 afisat:" read nf cat "$nf";; 2) echo "Introduceti numele fişierului sters:" read nf rm "$nf";; 3) fin=y echo "Iesire din program..." sleep 5;; *) echo "Opţiune invalida!";; esac done

ce

va

fi\

ce

va

fi\

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() {

} go $1

cd $1 PS1="`pwd`>"

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 7.6.1

Mediul Shell 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 sort ... wait wait hugefile > outfile1& pid1=$! hugefile > outfile2& pid2=$! $pid1 $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 semnalului 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Semnal Semnificaţie semnal special shell ce determină execuţia unei comenzi la ieşirea din shell terminal hangup întrerupere (DEL - tastă apăsată) quit (s-a apăsat CTRL+\) instrucţiune ilegală trace/breakpoint trap abort emulation trap excepţie aritmetică semnal kill eroare bus segmentation fault bad system call broken pipe alarm clock terminated

SIGHUP SIGINT SIGQUIT SIGILL SIGTRAP SIGABORT SIGEMT SIGFPE SIGKILL SIGBUS SIGSEGV SIGSYS SIGPIPE SIGALARM SIGTERM

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 7.7.1 Comenzi interne 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 test.cmd test.cmd test.cmd test.cmd -a -abc -a -b -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 opţiunii Opţiunea echo Comanda sh –x nume_script Explicaţii Afişează fiecare linie a script-ului după substituirea variabilelor, înaintea execuţiei Afişează fiecare linie a script-ului înaintea execuţiei, exact aşa cum a fost scrisă Interpretează dar nu execută comenzile Urmăreşte execuţia unui script Opreşte urmărirea execuţiei unui script

Opţiunea verbose Opţiunea noexec Setează echo-ul Resetează echo-ul

sh –v nume_script sh –n nume_script set –x set +x

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 5449 tty1 00:00:00 5465 tty1 00:00:00 5472 tty1 00:00:00

CMD sh bash 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 10 11 12 13 14 15 umask 022 fi USER=’id -un’ LOGNAME=$USER MAIL=”/var/spool/mail/$USER” HOSTNAME=`/bin/hostname` 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 2 3 4 #.profile # Fisier de configurare initiala ce se executa atunci cand # se utilizeaza shell-ul sh sau nu exista fisierele # .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 read raspuns read r1 r2 read read -a nume_vector read -e read -p prompter read -r linie Semnificaţie Se citeşte de la tastatură în variabila raspuns Se citeşte de la tastatură în variabila r1 până la primul caracter whitespace sau Enter, apoi în variabila r2 Se citeşte în variabila internă REPLY Se citeşte o listă de cuvinte într-un vector denumit nume_vector Se foloseşte în shell-ul interactiv Afişează un prompter, aşteaptă input-ul şi stochează rezultatul în variabila REPLY 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 ghilimele, corect este: numar=”6 + 9”) $ numar=4*5 $ echo $numar 20

de

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 2 3 4 Anderson, R. Bach, M.J. Brăescu, C. L., Dudaş, L. Burtch, K.O. UNIX File system Administration, Sams Publishing, 2002 The Design of the UNIX Operating System, Prentice Hall, Englewood Cliffs, N.J., 1986 Internet pentru începători, Bucureşti, Editura TIMS, 1995 Linux Files, Users and Shell Customization with Bash, Sams, Developer’s Library, 2004 Tru64 UNIX Documentation Overview, Compaq Computer Corporation, Houston, Texas, USA, 1999-1 Tru64 UNIX Security, Compaq Computer Corporation, Houston, Texas, USA, 1999-2 Mastering Linux, sec. Edition, USA, Sybex, 2001 Network Security, prezentare Cisco Seminar Series, 1998 Sisteme de operare MS-DOS şi UNIX, Bucureşti, Editura Viaţa Românească, 1994 Sisteme de calcul şi operare, Bucureşti, 1995/1 Sisteme de calcul şi operare, Bucureşti, Editura Aldo, 1995 Sun Enterprise Cluster 2.2, articol PC Report, noiembrie 1999 The Internet Complete Reference, 1993

5

Compaq

6

Compaq

7 8 9

Danesh, A. Michael, J. David, N. Dodescu Gh., Vasilescu, A. Dodescu, Gh., Năstase, F. Dodescu, Gh., Năstase, F Done, G. Hahn, H., Stout, R.

10 11 12 13

199

UNIX

14 15 16 17 18 19 20

Hall, E. A., O'Reilly, & Assosiates Kurose, J. Keith, R., Wesley, A. Lammle, T. McMullen, J. Myers, D., Lorenz, J. Năstase, F. Pănoiu, Al.

Internet Core Protocols: the definitive guide, Inc., 2000 Computer Networking, A Top-Down Approach Featuring the Internet, 2001 CCNA Study Guide, Second Edition, Sybex, 2000 Advanced UNIX user’s handbook, Prentice Hall PTR, 2000 Fundamentals of UNIX Companion Guide, Cisco Systems Inc., 2002 Arhitectura reţelelor de calculatoare, Bucureşti, Editura Economică, 1999 Compaq Tru64 UNIX, articol PC Report, iunie 1999 GNU/Linux: o alegere morală?, articol PC Report, noiembrie 1999 UNIX user’s handbook, sec. Edition, Prentice Hall PTR, 2002 UNIX Shells by Example, third edition, Prentice Hall PTR, 2002 Puneţi Linux-ul la treabă, articol PC Magazine, februarie 2000 Intranet, Bucureşti, Editura ASE, 1999

21

Pitiş, A.

22 23 24 25

Poniatowski, M. Quigley, E. Rosch, L. W. Roşca, I. G., Ţăpuş, N., Cristea, V., Atanasiu, I., Costinescu B., Năstase, F., Stanciu, C., Paiu, O., Godza, G.

200

Bibliografie

26 27 28 29 30 31 32 33 34 35

Sage, G. R. Stallings, W. Stevens, W. R. Tanenbaum, A. Tanenbaum, A. Taylor, D. Toxen, B. Vasilescu, A. Wrightson, K., Merlino, J. Zota, R. D.

UNIX pentru profesionişti, Timişoara, Editura de Vest, 1992 Operating Systems, fourth edition, Prentice Hall PTR, 2001 UNIX Network Programming, Prentice Hall, Englewood Cliffs, N.J., 1990 Computer Networks, 3rd ed., PrenticeHall, 1996 Reţele de calculatoare, Târgu Mureş, Editura Agora, 1998 UNIX Disk Usage, Sams, informIT.com, Ianuarie 2003 Linux Security: The Seven Most Deadly Sins, Prentice Hall PTR, 2003 Reţele de calculatoare, Bucureşti, Editura Inforec, ASE 1999 Mastering UNIX, USA, Sybex, 2001 UNIX – interacţiunea dintre procese şi kernel, lucrare la Simpozionul Naţional de Informatică Craiova, 1998 Sisteme de operare pentru reţele de calculatoare, Bucureşti, Editura Economică, 2002 Sistemul de operare UNIX - Utilizare şi programare shell, Bucureşti, Editura ASE, 2003

36

Zota, R. D.

37

Zota, R. D.

201

Sign up to vote on this title
UsefulNot useful