pipeline-ok

Fórumok

sziasztok!
fel mondatban: lehet-e bash alatt (p1 + p2) | p3 pipeokat szepen kesziteni?
kicsit reszletesebben: ugye az van, hogy ha van p1 es p2 program, es ha p1 eredmenyeit letaroljuk egy f1 file-ba, majd p2 ezt a file-t hasznalja mint bemenet, es a p1 ill p2 programok megfeleloen parameterezheto"ek, akkor egy p1 | p2 hivassal megsporolhato az f1 file mint olyan (ugy enbloc, diszk i/o, stb.)
kovetkezo" az alapproblema, ugy altalanosan: van p1, p2 es p3 program, p1 es p2 kimenete f1 es f2, p3 pedig f1-et es f2-t dolgozza fel. tegyuk fel, hogy mindegyik p* program rendelkezik egy "--input-*" es egy "--output" kapcsoloval, ahova barmit megadhatunk amint [f]open()-nel megnyit, rendre olvasassal es irassal, ezekrol veszi a bemeneteket, es amennyiben kihagyjuk, akkor az stdin/stdout-rol/ra olvas/ir. p3-nak ertelemszeruen az egyik --input kotelezo, hiszen ket kulonbozo bemenetrol van szo, es csak egy stdin van alapertelmezesben (mondjuk ugy, hagyomany szerint).
kerdes, hogy klasszikus shell (sh, bash) kornyezetben megoldhato-e ez a (p1 + p2) | p3 pipeline, ugy hogy f1 es f2 ne keletkezzen le? az --input-* / --output kapcsolokat ill ezek letezeset ezert is "taglaltam" reszletesen, hogy ezeket lehetne/kellene hasznalni. nyilvanvaloan implementalhato a dolog alacsonyszinten (pl c-bol megfelelo" pipe(), fork(), dup2(), close(), execve() kombinaciokkal), ugy hogy a p* programokat ne kelljen modositani; azaz mindez relative kulturaltan (pl olvashatosag feladasa nelkul) megoldhato-e? ilyesmi ezkozhasznalattal elve, mint & es ; operatorok, (...subshell...), sima pipe, 1>& 3 tipusu atiranyitasok, --input /dev/fd/3 tipusu bemenet, stb? latott valaki ilyet?
(amihez kene az massziv parhuzamositott adatfeldolgozas, f* fileok 50-100-200-... megasak, van beloluk tobb szaz megfelelo bemenet, 8-16 mag csamcsogna ezen egyszerre, stb, tehat a diszk i/o megsporolasa az nem lenne baj).
thx, a.

Hozzászólások

Nem értem, hogy a te jelölésedben a + operátor mit csinál, de bash-ben a ( echo a ; echo b ) |wc -l a végén 2-t ír ki.

mindez c-ben, valahogy igy kepzelheto" el:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc,char *argv[])
{
 int    p1[2],p2[2];
 int    pid1,pid2,pid3;

 pipe(p1);
 pipe(p2);

 /* launch `cat x.dat`: */
 if ( (pid1=fork())==0 )
  {     close(p2[0]);close(p2[1]);
        close(1);
        close(p1[0]);
        dup2(p1[1],1);
        close(p1[1]);
        execl("/bin/cat","cat","x.dat",NULL);
  } 
 /* launch `cat y.dat`: */
 if ( (pid2=fork())==0 )
  {     close(p1[0]);close(p1[1]);
        close(1);
        close(p2[0]);
        dup2(p2[1],1);
        close(p2[1]);
        execl("/bin/cat","cat","y.dat",NULL);
  }
 /* launch `paste /dev/fd/3 /dev/fd/4`: */
 if ( (pid3=fork())==0 )
  {     int     f1,f2;
        f1=dup(p1[0]);
        f2=dup(p2[0]);
        close(p1[0]);
        close(p2[0]);
        close(p1[1]);
        close(p2[1]);
        dup2(f1,3);
        close(f1);
        dup2(f2,4);
        close(f2);
        execl("/usr/bin/paste","paste","/dev/fd/3","/dev/fd/4",NULL);
  }

 sleep(1);

 return(0);
}

mukodik, persze par dolgot lehetne szebben csinalni, de most nem az a lenyeg (pl sleep helyett wait-ek + sigchild, ill a paste inditasakor szebben kene garantalni hogy a 3-as es a 4-es fd jojjon le'tre, stb).

Tudjuk hogy p3 hogyan dolgozza fel f1-et es f2-t?
Tehat eloszor beolvassa f1-et, majd f2-t, vagy egy sor f1-bol egy sor f2-bol, vagy...?

barmi lehet. nem is igazan szo"vegfile-ok ezek, nehol az van, hogy igy kicsit ebbol, kicsit amabbol, kicsit harmadikbol, majd ujra az elso"bo"l olvasgatunk, stb. tehat altalanos megoldas kellene. lasd fenti pelda (talan egyszerubb lett volna ezzel kezedni, az a cat/paste szerintem elegge demonstrativ, legalabbis a bevezetoben leirt rizsazashoz kepest).

man bash, /process substitution


paste -d ' ' \
    <(printf 'alma\n'; printf 'korte\n') \
    <(printf '1\n'; printf '2\n') \
| column -t

kimenet:


alma   1
korte  2

Szerkesztés: természetesen szándékosan írtam 2 db printf-et mindegyik <()-be, ui. ezzel jeleztem, hogy az ott egy rendes subshell. Tehát például azon belül további átirányítást lehet csinálni (az stdout átirányításának nyilván nincs értelme, mert azt akarjuk a pipe-ba/FIFO-ba küldeni, de az stdin joggal átirányítható szükség esetén).


paste <(filter1 <input1) <(filter2 <input2)