[rlug] Pipe/redirect

Petru Rațiu rpetre at gmail.com
Sun Jul 29 13:24:11 EEST 2018


2018-07-29 11:53 GMT+03:00 Petru Rațiu <rpetre at gmail.com>:

>
>
> 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.
>
>

Update: dupa ce am mai dat niste clickuri prin taburile deschise in urma
mailului de mai sus, am dat de o jucarie numita pipexec:
https://github.com/flonatel/pipexec , pare sa fie impachetata cel putin in
Debian deci probabil si pe alte distributii. Asta ar rezolva mai elegant
partea de sintaxa a "cum conectez ambele pipe-uri la acelasi proces", dar
nu te scapa de cum faci sa nu le pierzi in timp ce te joci cu ce-ai citit.

-- 
P.



More information about the RLUG mailing list