[rlug] Pipe/redirect
Petru Rațiu
rpetre at gmail.com
Sun Jul 29 11:53:04 EEST 2018
2018-07-29 9:48 GMT+03:00 tiberiu socaciu <tibisocaciu at gmail.com>:
> Pe 28.07.2018, Nicu <lucrari.in.pregatire at gmail.com> a scris:
> > 2018-07-28 1:53 GMT+03:00 MOROIANU Dragos <dmoroian at yahoo.com>:
> >> [dmoroianu at hpchn01 ~]$ mkfifo t.bc
> >>
> >> [dmoroianu at hpchn01 ~]$ bc < t.bc
> >> acum intr-un alt terminal:
> >> [dmoroianu at hpchn01 ~]$ echo "2+3" > t.bc
> >> programul afiseaza '5' si iese fara sa mai astepte comanda 'quit'.
> >> Cum conving programul sa astepte si alte comenzi si sa iasa doar dupa ce
> >> ii trimit 'quit'?
> >
> > mkfifo t.bc
> > bc < t.bc
> > ...
> > exec 7>t.bc
> > echo 2 + 3 >&7
> > echo 4 + 5 >&7
> >
> > ideea e sa tii FIFO-ul deschis; altfel, in momentul in care o comanda
> > de forma 'foo >out' a fost executata, toti descriptorii care au fost
> > deschisi prin redirectionari sint inchisi, indiferent daca 'foo' e un
> > proces separat sau o comanda built-in; iar cind capatul de scriere al
> > unui FIFO e inchis, procesul din celalt capat primeste un EOF.
>
> si care e diferenta dintre > si >> in acest caz?
> m-ati facut curios cu thread-ul asta si am inceput sa caut putin
> despre fd-urile la stdin, stdout, sderr in caz de redirectare
>
Foarte multe lucruri scrise pe jumatate in threadul asta. Probabil ca un
punct bun de plecare ar fi man 7 pipe.
1. un pipe e un buffer in care un proces scrie si altul citeste, fiecare
din ele vede capatul lui ca pe un file descriptor. Procesul care citeste
citeste cu blocking[*] reads, astfel incat atunci cand se intoarce cu zero
bytes, e tratat ca eof (celalalt a inchis pipe-ul). Procesul care scrie
scrie si el cu blocking[*] writes si trece mai departe fie primeste
semnalul SIGPIPE si write() se intoarce cu eroarea EPIPE (din cate inteleg
amandoua simultan, ca sa poti alege cum le tratezi, nu mi-e foarte clar).
2. In mod traditional, sculele de unix construite in jurul conceptului de
"mancam date de la stdin, le transformam cumva si le scriem la stdout"
trateaza inchiderea prematura a oricareia din cele doua pipes ca sfarsitul
programului (probabil cu diverse chestii de cleanup, gen blocul END la awk,
sau mesaje de eroare ca i-a disparut stdout).
3. In shell, simbolurile | , >, <, <(), >(), etc sunt instructiuni pentru
shell sa conecteze intre ei sau cu fisiere externe descriptorii proceselor
copil. In particular, >> seteaza O_APPEND pe callul de open() din spate, ca
sa deruleze fisierul la sfarsit, in rest e fix acelasi lucru ca >. (vezi
sectiunea REDIRECTION din man bash, de exemplu).
4. STDIN, STDOUT, STDERR nu sunt "magice" decat prin faptul ca sunt
standard (posix? c89? habar n-am, asa au zis inaintasii(TM)). Orice program
se asteapta sa aibe fd[0] deschis pentru read si fd[1] si fd[2] deschise
pt. write (asa le primesc de la procesul parinte). Poti sa mai ai si altele
deschise, dar daca le dai unui proces copil, ala trebuie sa stie cumva sa
se uite la ele.
Problema cu "tinem in acelasi proces pipe-urile si stdin si stdout la
procesul de controlat si scriem chestii pe baza a ce citim" e tricky de
rezolvat in bash in principal din cauza faptului ca orice scrieri si citiri
trebuie facute in subshellul care are cei doi file descriptori deschisi,
iar traditional programarea in bash utilizeaza o gramada de subshelluri, de
exemplu daca ai o linie cu | in ea, tot ce e in dreapta pipe-ului e in alt
subshell, care nu mai are acces la cei doi file descriptors (si din care nu
poti exporta simplu variabile, etc). La fel si cu backticks, etc.
E doable, da, dar poate deveni repede complex sa faci chestii in pure bash.
Daca programul ala e ceva gandit sa fie utilizat interactiv de un user la
terminal, recomandarea mea e in continuare expect. Daca e altceva gandit cu
o aplicatie in minte, e plauzibil sa aibe deja un client care vorbeste
api-ul ala, e nitel de masochism sa incerci sa-l scrii in bash.
[*] in mod normal, poti atat scrie cat si citi din pipe cu O_NONBLOCK, dar
din cate imi dau seama, comenzile traditionale unix nu fac asta. Oricum,
asta nu schimba cu mult comportamentul, eof e tratat la fel.
PS: E posibil sa-mi fi scapat anumite chestii sau sa ma fi exprimat aiurea
in unele locuri (nu ma pot lauda ca am facut system programming), dar sunt
destul de sigur ca esentialul e corect. As dori sa multumesc sectiunilor 2
si 3 din linux man pages care au facut posibil acest mail.
--
P.
More information about the RLUG
mailing list