Shtresat softuerike për I/O

## Abstrakt 
Fillimisht do të shikojmë parimet e I/O,qëllimet dhe implementimi i I/O Software-it nëpër shtresa të ndryshme,llojet e tyre dhe më pas studimin e I/O konceptit në pikpamjet e Sistemit Operativ.

## Parimet e I/O paisjeve 
:Input/Output është një nga termet kryesore kur bëhet fjalë për komponentat krysore të sistemit kompjuterik.Por që të kemi një komunikim ndrmjet sistemit dhe I/O paisje duhet të kemi parasysh se ç’do e tillë duhet të ketë kontrolerin e vet specifik(device controller). Nvarësisht nga tipi i kontrolerit, ai mund të jetë përgjegjës edhe për më shumë I/O paisje.
p.sh: SCSI(small computer system interface) mund të ketë të bashkangjitura plot 7 paisje pa problem.
*Device Controllers* mirëmbajn bufferin lokal përkatës dhe gjithashtu një set regjistrash qëpërdoren për qëllime specifike të tyre.Këto kontrolera janë të përgjegjshëm për zhvendosjen/transferimin e të dhënave ndrmjet paisjeve periferike dhe bufferave lokal të tyre. Madhësia e këtyre *bufferave* të paisjeve varion, varësisht se ç’farë tipi të paisjes kontrollon.

## Qëllimet dhe shërbimet e I/O Software-it 
Me *device independence* nënkuptojmë që mund të shkruhen programe të cilat na mundosojnë që ndonjë paisje hyrëse/dalëse pa patur specifikimin e paisjes përpara të njihet nga SO. Për shembull, programi që e lexon fajllin e futur mund të jetë i aftë të lexoj fajllin në flopy disk, në harddisk ,ose në CD-ROM, pa nevoj të modifikoj programin për secilën paisje të ndryshme. Kjo është arritje për sistemin operativ është e madhe, për vet faktin se këto njësi vërtet janë njësi të ndryshme dhe urdhërojnë me komanda të ndryshme për shkrim/lexim por ne nuk duhet të rishkruajmë nga fillimi Sistemin Operativ për tia përshtatur asaj paisjeje.
Tentohet që të gjitha të ndjekin modelin e njejtë dhe të kenë një interfejs të përafërt.

Shfrytëzimi i Input/Output komponentës është ndarë në nivele si në grafikun në vijim:

Shohim se *Interrupt handler* në grafik luan një rol kyç për sa i takon se si realizohet puna ndrmjet paisjeve.Zakonisht ato përdorin po të njejtin mekanizëm si *exceptions* dhe *traps*.
Kur interruptet ndodhin,CPUja ruan gjendjen procesive duke u hedhur në rutinën e interrupt handlerave në një adresë fikse memorike.Rutina e interruptit është e caktuar nga një *interrupt vector*.

Më poshtë do ilustrojmë me tabelë rutinën e *interrupt-handler* vektorit në **Intel Pentium** procesorët:

Rrjedhoja tipike e një kontrolle nëpërmjet I/O shtresave(*layers*) kur I/O bën kërkesë/dërgesë paraqitet kështu:

Me ***Uniform Naming*** nënkuptojmë se emri i resursit, i njësisë apo fajllave duhet që të jetë vetëm *string* ose *integer* dhe jo i varur nga niveli fizik i harduerit tyre.Pra virtualizimi i lokacioneve fizike adresore na mundëson që ne si shfrytëzues leht ti qasemi resurseve të cilat në një mënyrë apo tjetër janë të mapuara me të dhënat që ndodhen në paisje.
p.sh:
Në UNIX, të gjith disqet mund të jenë të bashkuara në hierarkinë e fajll sistemit në mënyrë të paarsyeshme prandaj përdoruesi nuk ka nevoj të jetë i informuar se cili emër i përgjigjet cilës njësi. Për shembull, floppy disk mund të jetë i caktuar në të majtë të direktoriumit ***/usr/ast/backup*** prandaj kjo kopjohet në ***usr/ast/backup/monday*** i kopjon fajllat në flopy disk.
Problem tjetër për I/O software është ***Error Handling***. Në përgjithësi gabimet mund të ndodhin rastësisht dhe të trajtohen në mënyrë izolative brënda-për-brënda harduerit, duke u munduar vet hardueri ta përmisoj gabimin e vetë,nëse kjo gjë është e mundur.
Nëse kontrolleri dështon në këtë fazë,pra nuk e ka të mundur që ta godis gabimin e zbuluar atëherë hapësira i lihet driverëve të njësisë që të trajtojnë atë gabim, ndoshta dhe duke tentuar që të dhënat e dëmtuara ti lexojnë në një cikël të pafund ose thjesht të injorohet vetë gabimi.

Cekim se mënyra e transferi të këtyre paisjeve ka të bëjë shumë edhe me efikasitetin e komunikimit ndrmjet sistemit kompjuterik dhe I/O paisjeve.

:Kemi **2 mënyra** të transferit:
* **Sinkron** (*synchronous*)
* **Asinkron** (*asynchronous*)
d.m.th kemi transfer të sinkronizuar ku të dhënat ndahen në korniza të caktuara e transmetohen për tu pranuar nga paisje me të njejtat kapabilitete.Transferi asinkron realizohet ashtu që transmetimi i gjatësisë së sinjalit nuk është i limituar si kundër te transferi i sinkronizuar,pasi duhen vetëm 2 bit(biti startues dhe ai mbyllës) që të mund ti definoj madhësinë e sinjalit. Kjo mënyrë adapton komunikimin ,ashtu që edhe 2 paisje me frekuenca të ndryshme punuese mund të komunikojnë mes veti.
Me transfer të sinkronizuar nënkuptojmë që të dy paisjet para se të fillojë transmetimi i të dhënave resetojnë *counterët* numerik të tyre dhe fillojnë të komunikojnë duke ndjekur kohën(clock).Zakonisht kur pranuesi ka pranuar informatat e dërguara dhe konekcioni veç më është stabilizuar, ai i kthen sinjal paisjes dërguese rreth asaj se ç’ka ka pranuar,prandaj transferi sinkron vlerësohet si më i sigurtë pasi që në ndërkohë mund të bëhen edhe algoritme të shikimit dhe rregullimit të gabimeve të vogla që mund të ndodhin gjatë transmetimit të sinjalit. Kompanitë e mëdha zgjedhin që të implementojnë transferin asinkron në shumicën e paisjeve pasi që kushton më lirë se sa transferi sinkron.

Shumë paisje fizike I/O janë jo të sinkronizuara-ku CPU fillon transferin dhe ndalet të bëjë diqka derisa arrin *interrupt*(ndërprerje).Programet e shfrytezuesit janë shumë më të lehta për të shkruajtur nëse I/O operacionet janë në bllokim –pas leximit të thirrjes sistemore programi është automatikisht i varur derisa të dhënat janë të arritshme në *buffer*.
Kjo tek sistemet operative të krijojnë operacione që janë aktualisht *interrupt-driven* në bllokim për *user programs*.

***Buffering*** është poshtu një koncept i rëndësishëm pasi që siguron vend në memorie dhe raun të dhëna në hapësirën e kernelit përderisa kryhet transferi ndërmjet paisjes dhe vetë aplikacionit. Ai ka për detyrë të adabtojë serviset të cilat ndërmjet veti kanë dallim shpejtësi të transferit(*si p.sh: fragmentimi i transferit të të dhënave në rrjet përmes paketeve*)
Kemi disa lloj mënyrash të I/O moduleve sipas këti koncepti:

Koncepti final që referohemi këtu është ***sharable*** vs. ***dedicated*** që i dedikohet njësive.
Disa njësi hyrëse/dalëse,p.sh. disku mund të përdoret nga më shumë përdorues në të njëjtën kohë.Nuk ka problem nëse shumë përdorues kanë të hapur *file*-in në të njëjtën kohë.
Ndrsa njësitë tjera, si p.sh. *tape drives* kanë për detyrë ti kushtohen një përdoruesi, të përfundoj ai,mandej përdoruesi tjetër mund të ketë qasje në atë resurs.
Duke pasur parasysh se sistemi has ne konflikt nëse 2 apo më shumë përdorues shkruajnë në blloqe të përziera mbi të njëjtën *tape*, si rrjedhojë e vetë *driveverave*. Paraqitja e njësive të dedikuara gjithashtu paraqet një shumë problemesh ,sikurse janë ***deadlock***-ët.
Përsëri sistemi operativ mund të jetë i përshtatshëm për të trajtuar të dyja rastet: njësit e ndara dhe të dedikuara në mënyrë që të menjanohen problemet.

:Ketu kemi 3 mënyra që I/O mund të jetë e përmbushur , ato janë:
* ***Programmed I/O***
* ***Interrupt-driven I/O***
* ***I/O me DMA***

## Programmed I/O 
Forma më e thjeshtë për I/O është të kenë CPU që ti bëjë të gjitha punët, e kjo metodë emërtohet me Programmed I/O.
Për ilustrim marrim një shembull,konsiderojmë se përdoruesi dëshiron të printoj tetë karaktere të tipit string”ABCDEFGH” në printer.P.sh.,
Në këtë figurë paraqitet skema ku përdoruesi sigurohet për printerin nëse është i kyqur ose jo.Nëse printeri është i kyqur në ndonjë proces tjetër atëherë kemi dështim dhe si output duhet të kthehet kodi i gabimit ose kemi bllokim derisa printeri të jetë në status të gatshëm për parametrat e thirura nga sistemi operativ.Përndryshe nëse printeri është i gatshëm përdoruesi krijon thirrjen sistemore duke i thënë sistemit operativ të printoj stringun(”**ABCDEFGH**”) në printer.
thumb|upright=0.6|Figura a)
Mandej sistemi operativ e kopjon në buffer-in së bashku me stringun në rresht ,dërgon p,në hapsirë të Kernel-it,kur ajo është më së lehti për qasje.Mandej nëse printeri është i kyqur sistemi operativ kopjon karakterin e parë në regjistrin e të dhënave në printer, në shembullin tonë duke përdorur Memory-Mapped I/O.Ky akt e aktivizon printerin,nëse karakteri nuk ka arritur ende ajo ndodh ngase disa printer nuk prinotjnë asgjë menjëherë pas buffer a line.Në fig.b) shohim se shkronja e parë printuar dhe sistemi ka markuar shkronjën e dytë ”B” që duhet të printohet.
thumb|upright=0.6| Figura b)
Kur shkronja e parë është e printuar sistemi operativ kontrollon nëse printeri është gati të pranoj stringun tjetër.Në përgjithësi,printeri ka regjister të dytë , i cili e ka këtë strukturë.Veprimi(akti) për shkruarjen në data register shkakton që nga gjendja e gadishmërisë të kaloj në gjendje të zënë.Kur printeri e proceson karakterin pasues,tregon atë se është i gatshëm të vendos disa bit-a në status regjistër ose të vendos një vlerë në të. Gjatë kësaj kohe sistemi operativ pret që printeri të jetë i gatshëm përsëri,kur printeri është gati atëherë printohet karakteri tjetër, kjo procedurë vazhdon gjersa të jetë printuar i gjithë stringu”ABCDEFGH”.Mandej kontrolli kthehet te procesi i përdoruesit.
Gjithë këtë e përmbledhim kështu:
Të dhënat kopjohen në Kernel,mandej sistemi operativ i vendos karakteret për njëkohë të gjitha.Në aspekt të programmed I/O,pas vendosjes së karaktereve *CPU* vazhdimisht zgjedh njërin të shohë se a është gati të pranoj tjetrën,kjo sjellje shpesh është quajtur si *polling* ose *busy waiting*.
thumb|upright=0.6| Figura c)

**P.sh:**

**copy_from_user(buffer,p,count);** *p është Kernel-buffer*

**for(i=0;i

***Programmed I/O*** është i thjeshtë por ka disavantazhet e veta.(pengesa) për lidhje me *CPU* gjithë kohën derisa të gjitha operacionet hyrse/dalse janë të kryera.
Nëse koha për printim është e vogël atëherë ***busy_waiting*** është e mirë,përndryshe nëse në një sistem ku *CPU* nuk ka të bëjë me asgjë tjetër , ***busy_waiting*** është i arsyeshëm. Ndërsa në disa sisteme të kompleksuara kur *CPU* ka të punoj diçka tjetër, ***busy_waiting*** është i paefektshëm.

## Interrupt Driven I/O 
Tani të konsiderojmë një pjesë të printimit në printer që nuk ka në *buffer* karaktere por printon cila do që arrin.Nëse printeri mund të printoj, thotë 100 *character/sec*,kur secili karakter merrë 10 mili sekonda që të printohet.Kjo d.m.th pas ç'do karakteri që është shkruar në *printer’s data register*,*CPU* vendos vend bosh për 10msec pritje të jetë i pranueshëm të nxjerr karakterin e ardhshëm.Kjo më shumë se mjaft kohë të bëjë kontestin të shihet dhe të vazhdon me procese tjera,për 10 msec kjo mund të humbet.
Mënyra për ta lejuar* CPU *të bëjë diqka tjetër gjatë pritjes derisa printeri të jetë gati është të përdor *interrupt*.Kur sistemi thërret që të printohet *stringu* është kryer,*buffer* është kopjuar në hapsirën e ***Kernel***-it para se ne ta shohim dhe karakteri i parë është i kopjuar në printer derisa printeri të pranoj karakterin tjetër.Në këtë rast *CPU* thërret *scheduler* ose ndonjë proces tjetër që është në rrjedhim.Procesi që pyet që *stringu* të jetë i printuar është bllokuar derisa të printohet i gjithë *stringu*.

**copy_from_user(buffer,p,count); **
                  
**enable_interrupts();**

**while(printer_status_reg!=READY);**

**printer_data_register=p[0];**

**scheduler();**

Fig. a) Kodi i ekzekutuar kur printimi është kryer:

**if(count == 0)**

**{**

**unblock_user();**

**}**

**else**

**{**

**printer_data_register=p[i];**

**count=count-1;**

**i=i+1;**

**}**

**acknowledge_interrupt();**

**return_from_interrupt();**

Fig. b) Kodi kur kemi interrupt:

Kur printeri printon një karakter dhe është i gatshëm të pranoj tjetrin karakter,printeri shkakton një interrupt. Ky interrupt ndalon procesin i cili është duke u ekzekutuar dhe CPU-ja ruan kontekstin e procesit që ishte duke punuar në memorje. Mandej printeri ndalon procedurën shërbyese që është në rrjedhë.Nëse nuk ka më karaktere për printim,interrupti kap disa aksione që të hap përdoruesin. Përndryshe vendos karakterin tjetër,pranohet interrupti dhe kthehet te procesi i cili ishte në rrjedhim para interruptit, ku puna vazhdon prej aty ku ka mbetur.

## I/O me DMA 
Një pengesë e qartë e *interrupt-driven I/O* është se *interrupt* përsëritet tek secili karakter.Interrupti merrë kohë prandaj kjo skemë humb njëfarë vlere të kohës së *CPU*-së.Zgjidhja është të përdorimi i **DMA**(*Direct Memory Access*).
**DMA** kontroleri i furnizon të gjitha karakteret në printer për të njëjtën kohë,ashtu që *CPU* të mos jetë i bezdisur. Në esencë **DMA** është *programmed I/O* vetëm që **DMA kontroleri** e kryen gjithë punën në vend të *CPU*-së.Pra me një fjalë është një mikroprocessor që kryen transferat ndrmjet *I/O* paisjes dhe mpa angazhuar fare njësinë qendrore procesike që ti bëjë këto punë.

*Fig. a) kodi pa interrupt*

**copy_from_user(buffer,p,count);**

**set_up_DMA_controler();** 

**scheduler();**

*Fig. b) me interrupt*

**acknowledge_inerrupt();**

**unblock_user();** 

**return_from_intenrrupt();**

Avantazhi më i madh i **DMA** është reduktimi i një numri të *interrupt*eve prej 1 për karakter dhe 1 për *buffer* të printuar. Nëse kemi shumë karaktere *interrupt* është ende më i vogël, ky mund të jetë përmirësim i lartë.
Në anën tjetër fuqia e **DMA**’së zakonisht është shumë më e vogël se sa fuqia procesuese e *CPU*. Nëse **DMA kontroleri** nuk është i aftë për rritjen e shpejtësisë së njësisë ose *CPU* nuk ka çfarë të bëjë tjetër gjersa **DMA** pret për interrupt atëherë *interrupt-driven I/O* ose *programmed I/O* mund të jenë më efektivë.

## Application I/O interface 
Në këtë nëntemë do të shpjegojm strukturën e teknikës dhe interfejsin për sistemet operative që mundësojnë I/O paisjet të trajtohen në mënyrën standarde. Do të shpjegojmë si një aplikacion mund të hap një fajll në disk pa njohur se çfar disku është dhe sa disqe të rij janë dhe paisjet e tjera të mund të shtohen në kompjuter pa përçarjen e sistemit operativ. 
Si software-engineering problemet, që pranojnë këtu përfshim abstragim, encapsulation dhe software shtes. Specifikisht ne mund të abstragojmë detjaet e diferencës në I/O paisjet duke identifikuar disa tipe gjenerale. Çdo tip gjeneral aksesohet në formë standade të futjes së funksioneve. Dallimet janë të kapsuluara në modulet e kernelit të quajtura pajisjet drejtuese që brenda vendit janë me porosi të përshtatura për çdo pajisje.Fig d) ilustron se si I/O Pjesë lidhen me të kernelin dhe janë të strukturuara si shtresa në software.

thumb|center|Fig. d) A kernel I/O structure.

Qëllimi i pajisje-shtresë për të fshehur dallimet ndërmjet paisjes kontrollues nga I / O subsystemi i kernelit, si I/O thirrjet e sistemit encaplsulate sjelljen e pajisjeve të disa klasave gjenerik që fshehin dallime të hardware nga aplikacione. Marrja e I/O subsystemit të pavarur të hardwareit thjeshton punën e zhvilluesi të sistemit operativ, ajo gjithashtu përfiton prodhuesit hardware. Për më tepër dizajni i paisjeve të reja të jetë në përputhje me interfejsin ekzistues kontrollues (të tilla si SCSI - 2), ose paisje te shkruajtura për ndërfaqe hardware për sistemet operative të njohura. Kështu, ne mund të bashkëngjisim periferikësh të reja për një kompjuter pa pritur për sistemin e operimit që të zhvilloj kodin mbështetës. Për fat të keq për prodhuesit e hardware pajisjeve, çdo lloj i sistemit të operimit ka standardet e veta për interfejs pajisjet.

## Stream I/O System 
Në një version të ri të sistemit operativ **UNIX**, një dizajn fleksibil me bazë koroutine
zëvendëson lidhje tradicionale të ngurta në mes të proceseve dhe terminale apo rrjeteve. Përpunimi modular mund të jetë futur në mënyrë dinamike në një Stream që lidh një përdorues të programit tek një pajisje. Programet mund të lidheni direkt me programet, duke siguruar ndër-procesin e komunikimit.
### *Streams* 
Një stream është një lidhje e plotë-duplex në mes të procesit të përdoruesit dhe një pajisje apo pseudo-pajisje. Përbëhet nga disa lidhje lineare të përpunimit të moduleve, dhe është i ngjajshëm me një Shell Pipeline, përveç se të dhënat rrjedhin në dy drejtime. Modulet në një stream pothuajse ekskluzivisht komunikojnë duke kaluar mesazhet tek fqinjët e tyre. Me përjashtim të disa variablave konvencionale të përdorura për kontrollin e stream-it, modulet nuk kërkojnë qasje në ruajtjen e fqinjëve të tyre. Për më tepër, një modul ofron vetëm një pikë hyrje në çdo fqinjë, domethënë një rutinë që e pranon mesazhe. Në fund të stream-it afër procesit është një grup i rutinave që ofrojnë ndërfaqen për pjesën tjetër të sistemit. Një përdorues shkruan dhe I/O kontrolli i kërkesave është kthyer në mesazhet e dërguara në stream, dhe lexon
kërkesat të marra prej të dhënave nga stream-i dhe i kalon ata tek përdoruesi. Në fundin tjetër të stream-it është një device driver module. Këtu të dhënat vijnë nga stream që janë dërguar në paisje : karakter dhe gjendjen e tranzicionit të zbuluar nga ana e paisjes, të cilat janë të përbëra nga mesazhet të dërguara në stream drejt programit të përdoruesit.

## Drajverat e paisjes 
Ç’do I/O paisje i nevojitet kode të specifikuara për të patur mundësi që ajo të kontrollohet.Këto janë *device drivers* dhe shumica e paisjeve kanë drajverat e tyre për cilin do nga sistem operativ të njohtur që kemi.
Logjika e driverit kyesisht ekzekutohet në nivel e **kernel bërthamës** mirëpo ka përjashtime kur bëhet fjalë për mikroarkitekturën e cila ndonjëherë këto komanda i shtyn edhe në hapësirën e shfrytëzuesit(*user space*).
Pra siç thamë edhe më parë kemi : *block-device drivers*(disku,etj)dhe *character drivers*(tastiera,printerët)
Drajverat e paisjes kanë disa funksione siç janë:të startojë paisjen nëse është e nevojshme,të menaxhoj me fuqinë elektrike që ajo paisje shfrytëzon,ti pranoj abstrakt kërkesat nga softwearet përkatës për I/O paisjen dhe ti përkthejë ato në komanda specifike të I/O modulit,si dhe ndonjëherë të japë një raport me ngjaret e fundit.

## Ridrejtimi standart i I/O 
**Unix** e konsideron çdo pajisje të atashuar tek sistemi, sikur ajo të jetë një fajll. Default, një komandë e trajton terminalin tuaj si një fajll të hyrjes standarte, nga e cila të lexojë informacionin. Terminali juaj gjithashtu trajtohet nga komanda edhe si fajll e daljes standarte, tek e cila të dërgoj informacionin. Ky veprim mund të ndryshohet duke ridrejtuar hyrjen standarte dhe daljen standarte nga dhe tek një fjall tjetër. Pra sistemi operativ ju lejon ju të manipuloni hyrjen dhe daljen (I/O) e të dhënave tek dhe nga sistemi, duke përdorur komandat dhe simbolet specifike I/O. Ju mund të kontrolloni hyrjen duke specifikuar zonën nga e cila të merren të dhënat. Për shembull, ju mund të specifikoni të lexoni hyrjen si të dhëna të futura nga tastiera ( hyrje standarte ), ose të lexoni hyrjen nga një fajll. Ju mund të kontrolloni daljen duke specifikuar ku të shfaqen ose depozitohen të dhënat. Për shembull, ju mund të specifikoni të shkruani të dhënat dalëse tek ekrani ( dalje standarte ), ose t’i shkruani ato tek një fajll.

## Ridrejtimi me simbole i I/O 
Zakonisht një komandë lexon hyrjen e saj nga tastiera ( hyrje standarte ), e përpunon atë, dhe shkruan daljen e saj në ekran ( dalje standarte ). Gjithmon ju mund të specifikoni simbolet I/O të ndryshoni mënyrën si komandat të përdorin hyrjen dhe daljen. Për shembull, ju mund të drejtoni një komandë të lexojë hyrjen e saj nga një fajll, të shkruaj daljen e saj tek një fajll, ose të dërgoj daljen e saj tek një komandë tjetër.
Për të ridrejtuar hyrjen dhe daljen përdorim *simbolet* e mëposhtme :
	
	**	shkruan daljen standarte tek nje fajll**

	**>>	shton daljen standarte tek fundi i nje fajlli**

	**|	percjell (pipe) daljet nga nje komande tek nje komande tjeter**

### Ridrejtimi i hyrjes standarte 
Të ridrejtoni hyrjen standarte për një komandë, përdorni karakterin **
		**mail edi 
Komanda mail lexon hyrjen standarte nga fajlli **memo** dhe poston përmbajtjen e këtij fajlli tek përdoruesi edi.

**wc 

Komanda **wc** lexon si hyrje standarte informacionin nga *file1*, llogarit numrin e linjave, fjalëve dhe karakterëve në të dhe dërgon informacionin tek dalja standarte (në ekran).

### Ridrejtimi i daljes standarte 
Të dërgoni daljet tek një fajll, pra të ridrejtoni daljen standarte nga një komandë përdor simbolin **>** (*më e madhe se*) të ndjekur nga emri i fajllit së daljes (ku do të dërgohet dalja). Nëse fajlli në të cilin do ridrejtoni daljet standarte nuk ekziston, atëherë ai fajll do të krijohet automatikisht. Simboli **>** e udhëzon *shell*-in të fshijë përmbajtjen koherente të një fajlli dhe të shkruaj daljen e komandës tek ky fajll.

	Për shembull :

		**ls > file1**

Kjo dërgon daljen e komandës **ls** tek fajlli i quajtur **file1**. Nëse **file1** ekziston, *shell*i mbivendos mbi përmbajtjen e tij daljen e komandës **ls**. Nëse **file1** nuk ekziston, *shell*i e kriojn atë me përmbajtjen që na jep komanda **ls**.

Kur përdorni ridrejtimin e daljes standarte me simbolin **>** tek një fajll që ekziston keni kujdes, sepse gjarë ridrejtimit fjallit do ti mbivendoset dalja standarte duke fshirë të gjitha informacionet që fajlli ka përmbajtur më parë. 
Siç do e shohim edhe më poshtë ju mund të shtoni daljen standarte të komandës, në fundin e përmbajtjes së një fajlli ekzistues, kështuqë ruhen edhe informacionet e ruajtura më parë në fajll.
Nëse një komandë realizohet me sukses në ekran nuk do të shohim asnjë rezultat nëse ne thjesht nuk e thirrim fajllin në të cilin është ruajtur dalja standarte. E kundërta ndodh kur komanda nuk realizohet me sukses atëherë rezultati do të shfaqët në terminalin koherent, ose do të ridrejtohet në error fajllin nëse ja kemi caktuar.

Për shembull :

		**ls - | file1.txt**

		*file1 not found*

Komanda **ls** dështon sepse **file1.txt** nuk ekziston në direktorinë koherente. Mesazhi *file not found* është dërgurar në daljen standarte – *terminal*, që të na informoj ne për këtë. Kurse për ridrejtimin në error fajll metodat janë të ndryshme për *shell*-e të ndryshëm.

## Bibliografia 
# A. S. Tanenbaum, Modern Operating Systems: 2nd Edition, Prentice-Hall, 2001. 
# Dennis M. Ritchie, A StreamInput-OutputSystem.
# Windows Operating System Internals Curriculum Development Kit, developed by David A. Solomon and Mark E. Russinovich with Andreas Polze, 2005.
# A. Silberschatz, P. B. Galvin, G. Gagne, Operating System Concepts : 7th Edition, John Wiley & Sons, 2005.
# Bazat e Sistemeve të Operimit nga René Doursat
# V. Koliçi, Sistemi operativ UNIX : Tiranë, SHBLU, 1999.