RightFiles.com

How to Create a Good UNIX Interface [Romanian]

Original at: http://fmg-www.cs.ucla.edu/geoff/interfaces.html

Cum de a crea o interfață bună UNIX 

Introducere

Acest document a fost scris în 1994, pentru ca să introducă noi studenţi absolvenți şi programatori  cercetători în unele principii de bază ale design-ului bun de comandă a lui Unix. Odată cu apariţia Internetului, am decis să-l împărtășesc cu alții, în speranţa că cercetătorii noi nu v-or continua să facă aceleaşi greşeli simple.

Principiile de bază

  • • Faceți un filtru
    • A întoarce codurile de eroare
    • Manipulați cu  argumente multiple
    • Raport despre erori
    • Simplificați ieşire pentru a  uşura analiza
    • Faceți așa ca cazul implicit fie cel mai simplu
    • Nu face acesta interactiv implicit
    • Păstraţi opţiuni simple
    • Gândiţi-vă la modul în care celelalte programe vor utiliza acesta
    • Citiţi pe Kernighan şi Pike

Faceți un filtru

O mare parte din puterea UNIX-ului vine de la disponibilitatea canalurilor şi conceptul asociat de un filtru. Programe care sunt scrise pentru a fi filtre pot fi compuse din alte programe în moduri care autorul original niciodată nu aşteaptă. Anumite reguli trebuie să fie urmate pentru a face acest lucru posibil. Cel mai important dintre acestea este faptul că toate programele ar trebui să se compoarte (în măsura corespunzătoare) ca filtre. Acest lucru înseamnă că, în cazul în care ei acceptă un fişier de intrare, acestea ar trebui să-l citească implicit. În cazul în care ea face ca majoritatea programelor, produce ieşire, ei trebuie să-l pună la iesirea standartă, astfel încât să fie uşor de procesat într-un canal sau în ghilimele inverse.

Este destul de comun pentru programele de a accepta numele fişierului de intrare pe linia de comandă (priviți mai jos). Cu toate acestea, numai în situaţii foarte rare, un fişier de ieşire ar trebui să se acorde pe linia de comandă, mai degrabă decât prin redirecţionarea producţiei standarte. Excepţia cea mai comună există atunci când sunt mai multe fişiere de ieşire, de exemplu, cele produse prin dividere (1). Un exemplu mult mai neobişnuit este sortarea (1), care are nevoie de comutator din cauza capacităţii de a suprascrie unul dintre fişierele sale de intrare (care nu poate fi realizat prin redirectare) - dar reţineţi că felul scrie tostdout în mod implicit. Un ultim exemplu este ld (1), care trebuie să cunoască numele fişierului de ieşire, astfel încât să puteţi seta modul de executare a biţilor. Dacă vă trebuie să oferiți absolut un fişier de ieşire specificabil, vă rugăm să folosiţi "-o" ca comutator, şi să scrieți la stdout în mod implicit.

Un punct final în istoria cu filtre este faptul că este critic de a scrie mesaje de eroare la stderr, mai degrabă decât stdout. Există două motive pentru acest lucru. În primul rând, aceasta înseamnă că va mesaje de eroare vor fi arătate utilizatorilor, mai degrabă decât să dispară din teavă (iată pentru ce stderr a fost inventat). În al doilea rând, aceasta înseamnă că programele de care au nevoie de a analiza filtrele de ieşire Dvs. nu v-or primi confuz de la mesajele de eroare care nu respectă formatul de ieşire standart.

A întoarce codurile de eroare

Un program care nu  întoarce un succes / eșuare proprie nu este numai neglijent, dar și greşit. Chiar dacă programul nu poate greşi, eventual, acesta ar trebui să se întoarcă totuşi la zero, atât pentru a preveni avertismente compilatoare cît şi (ce e mult mai important) să fac lucruri ca de exemplu  să nu se lase de aceea că ați întors în mod neintenţionat  statutul diferit de zero.

Dacă programul Dvs. poate eşua, întoarceți starea diferită de zero la eşec. Acest lucru face pe el mult mai util în script-uri. Atunci când nu e prea greu să faceți acest lucru, codurile de returnare ar trebui să fie semnificative, astfel încât apelanţii pot distinge diferite tipuri de erori.

Manipulați cu  argumente multiple

Multe programe acceptă numele de fişiere pentru a fi prelucrate într-un fel anumit. Dacă programul Dvs. procesează un fişier, ar trebui să vă întrebați dacă  ar fi posibil ca el să proceseze mai mult de un fișier într-un moment dat într-un mod semnificativ. Dacă este aşa, faceți efortul de a scrie un șablon peste argumente! (Acesta se aplică şi la argumentele non-fişierelor pentru unele programe; priviți lista de exemple de mai jos.) Aceasta nu înseamnă că aveți nevoie de un argument, în special, orice program care citeşte intrarea ar trebui să fie capabil să citească de la stdin, precum şi dintr-un fişier. Un mod simplu de a face acest lucru este de a scrie un cod cum ar fi următorul:

FILE *infile;
	int i;
	int error_status = 0;
	if (argc <= 1)
	    dofile (stdin)
	else {
	    for (i = 1;  i < argc;  i++) {
		infile = fopen (argv[i], "r");
		if (infile != NULL) {
		    dofile (infile);
		    fclose (infile);
		} else {
		    fprintf (stderr,
		      "sample-program:  Couldn't open input file '%s': %s\n",
		      argv[1], strerr (errno));
		    error_status = 1;
		}
	    }
	}
	return error_status;

NU luaţi cale de ieşire leneşă, scriind codul care procesează un singur argument şi apoi iese. Luaţi în considerare următoarea listă de programe, toate care ar fi putut fi scrise pentru a lua doar un singur argument (sau chiar pentru a citi doar de la stdin), şi gîndițivă mult mai mult  despre s aceea ce durere de cap ar fi Unix în cazul în care el aș face: rm, touch, more, sort, mkdir, cc, ls, mail

Raportați despre  erori

După cum se indică în exemplul de cod de mai sus, ar trebui să verificaţi întotdeauna rapoarte despre erori, şi să face acest lucru într-un mod semnificativ. Nu doar ieşiți în tăcere. Nu tastați "no input file", fără nici un ajutor. Este, de obicei admisă practica de a folosi perror (3), fără a da alte informaţii; utilizați strerr (3) în loc de aceasta, cum e arătat în exemplul.

(Strerr (3) nu este întotdeauna disponibil. Uneori este mascat sub forma strerror (3) Alte ori, la fel ca în SunOS 4.1.1, e nu doar acolo. Dar pentru asta nu este nici o scuză. Este uşor să punem în aplicare:

extern int errno, sys_nerr;
	extern char *sys_errlist[];
	char *strerr (num)
	    int num;
	{
	    static char nomsgbuf[24];
	    if (num == 0)
		num = errno;
	    if (num <= 0  ||  num >= sys_nerr) {
		sprintf (nomsgbuf, "unknown error %d", num);
		return nomsgbuf;
	    }
	    else
		return sys_errlist[num];
	}

Încercaţi să faceți mesajul de eroare cît de  posibil informativ. Țineți aminte, că cauza eroarei poate fi îndepărtată de simptome. De asemenea, identificați programul în fiecare mesaj de eroare (ca în exemplu). Nimic nu este atât de frustrant ca obținerea un mesaj de la o conduct de 5 programe, şi neînțelegerea care program a produs asta.

În cele din urmă, fiecare program ar trebui să emită un mesaj de utilizare atunci când s-a invocat în mod incorect. Dvs. nu trebuie să închipuiți ceva, dar ar trebui să dați cel puţin o listă pe o linie de argumente şi opţiuni.

Simplificați ieşire pentru a  uşura analiza

Pentru ca un filtru să fie util, trebuie să fie uşor pentru alte programe să analizeze ieşirea. Unix standart constă în aceea că producţia ar trebui să fie din linii unice care conţin un număr egal de câmpuri separate prin spaţii albe. În general, cîmpuri ar trebui să fie autoidentificate pe baza conţinutului lor, sau ar trebui să fie identificate printr-o linie de la început. În cazul în care este rezonabil pentru câmpurile să conţină spaţiu liber (de exemplu, câmpul numelui complet din fișierul parolei), este acceptabil să utilizaţi un separator diferit cum ar fi o coloanș, dar acest lucru ar trebui să fie o excepţie.

Ieşire de mai multe linii ar trebui să fie evitată ori de câte ori este posibil, deoarece este mult mai dificilă pentru analiza. În schimb, luați o cheie de la ls (1) şi ps (1): asta afişează informaţiile cele mai frecvente și de care este nevoie în mod implicit, şi aprovizionare comutatorilor care pot fi folosite pentru a imprima detalii, dacă asta este necesar. Dacă  aveți nevoie numai decît să produceți multilinie de ieşire, fiecare linie trebuie să înceapă cu o etichetă unică, astfel încât domenii de interes pot fi selectate cu un grep (1).

Un test simplu pentru calitatea ieșirii Dvs. este de a transmite programul Dvs. în "awk '{print $ 2}'". Dacă obţineţi rezultate sensibile, programul este probabil uşor de utilizat într-o conductă mai generală.

Faceți așa ca cazul implicit fie cel mai simplu

Când faceți un instrument pentru a organiză unele bit-uri de date pentru scopuri de depanare, există tentaţia de a imprima totul "doar în cazul în care o să am nevoie să văd." Dorinţa pentru completare este admirabilă, dar complet nu ar trebui să fie implicit. Instrumente cu prea multe cuvinte sunt grele pentru alegerea ieșirii dorite, să întîlnește cu prea multe linii de ieşire şi domenii inutile, şi poate duce la  comanda negative a comutatorilor ("specificați comutatorul d- dacă nu doriţi să vedeţi data").

În schimb, cred ca un pic despre ceea ce invocarea este cel mai probabil să vrei să vezi, şi să facă acest lucru implicit. Ls (1) este un exemplu perfect de acest lucru: în cazul implicit, tot ce se afişează numele fişierului. Dacă sunteţi în grabă, mâner doar două cazuri: default (scurt) de ieşire, şi putere maximă, de obicei, selectate de către "-l" sau "-o". switch-uri intermediare pot fi adăugate mai târziu dacă se dovedeşte a fi utilă pentru a selecta un subset de putere maximă.

Nu face acesta interactiv implicit

Aşa cum am spus înainte, puterea Unix-ului este bazată pe filtre. Cu excepţii extrem de rare, acest  lucru înseamnă că programele ar trebui să fie sensibil utilizabile de la linia de comandă. În mod implicit, instrucţiuni ar trebui să fie ajuns de la comutatori, și nu de la citire interactivă stdin. Este bine, şi, adesea, chiar și cu bun design de a oferi un mod interactiv ca o opţiune, dar caz implicit ar trebui să existe pentru a efectua acţiunile indicate pe linia de comandă şi apoi ieşiţe. Programe doar interactive sunt extrem de grele pentru utilizare în conducte (şi nu cred că există un singur program interactiv Unix pe care nu am gasit prilejul de a utiliza non-interactiv).

Păstraţi opţiuni simple

Ca regulă generală, fiecare comportament separat a unui program ar trebui să fie invocat de către un comutator separat opţional. Un bun exemplu în acest sens este wc(1), care are comutatori separați pentru a selecta cuvântul, linie, sau numărul de simboluri.Cu toate acestea, acest principiu poate fi dus prea departe. Luaţi în considerare că ls (1) are deja prea multe opţiuni. Dacă fiecare domeniu tipărit de "-l" comutator v-a avea propria opţiune liniei de comandă, ls ar fi aproape inutilizabil. Încercaţi să găsiţi un echilibru între a face o opţiune de a invoca funcţii legate de logică şi cei care au prea multe opţiuni.

Gândiţi-vă la modul în care celelalte programe v-or fi utilizate

Ultimul, dar nu cel mai ultim, întotdeauna țineți aminte că construiți un instrument care va fi o componentă a altor instrumente. Intreabați-vă cât de uşor este de a invoca programul Dvs. de la un script, cum puteți uşura ieşirea la proces, şi ce funcţionalitate ar putea fi utilă și  pe care nu o aveţi încă. Dacă faceți aceste lucruri, programul va avea o viață lungă și fericită.

Citeste pe Kernighan şi Pike

Daca exprimați seriozitate  pentru a fi un programator Unix, ve-ți primi o mare  favoare dacă procurați şi citiţi cu atenţie o copie a cărții "The Unix Programming Environment" de  Brian Kernighan și Rob Pike. Această carte este o introducere foarte bună în corpusul programării şi la metodele de instrumente de amenajare împreună , care fac Unix un astfel de sistem bun  pentru oamenii de ştiinţă serioși.


Înapoi la pagina lui Geoff Kuenning
Această pagină este menţinută de Geoff Kuenning.