Azt szeretném, hogy amit egy programból named pipe-ba írok, azt awk-ban getline-nal el tudjam olvasni. A probléma viszont az, hogy ez blokkolós. Van egy ciklusom, amelynek futnia kell, s ha a named pipe-ba bejött egy sor, akkor azt átvenném getline-nal.
if ((getline row <pipe)>0) {
printf("%s\n", row);
}
Ez a próbálkozásom. Ami szörnyű, hogy blokkolós, bent marad a getline-ban, amíg egy másik programból nem írok a pipe-ba. Utána már megy, csak az elején teszi ezt velem.
- 249 megtekintés
Hozzászólások
Nem azert blokkol mert az awk kozben olvasna be a kovetkezo sort? Probald ki igy:
awk 'BEGIN { while ( 1 ) { if ((getline row < "/tmp/fifo")>0 ) printf("[%s]\n",row); } }'
Nehezites hogy ugy latom /tmp/fifo-t mintha csak 1x nyitna meg a munkamenet soran. Igy ha a masik program ilyen echo whatever > /tmp/fifo jellegu parancsokkal eteti akkor jo kerdes hogy mi tortenik. Ez is bekavarhat, nem?
- A hozzászóláshoz be kell jelentkezni
A másik oldal értelemszerűen így eteti, különben nem lenne nagyon értelme. Amit írtam, az a BEGIN szekcióból hívott függvényben van. Az egész awk programom a BEGIN szekcióban van lényegében. A feladat nem kifejezetten awk-ra való, én lényegében egy C-szerű scriptnek használom az awk-t. :) Valójában egy hardware-nek küldök parancsokat, és azt akarom megoldani, hogy ha már egy példányban fut ez az awk program, mert oszcillogrammot rajzol valós időben, akkor ne okozzon kommunikációs zavart, hogy aszinkron módon küldök a hardware-nek parancsot. Sokkal inkább létrehoz az első awk - nyilván shell visszahívásával - egy named pipe-ot, a másik awk program ilyenkor beírja ebbe a mondanivalót, az első felszedi, s merge-eli az amúgy is küldött parancsok láncolatába.
Majdnem működik, csak az a bajom, hogy megáll a getline-ban. Próbáltam úgy kirúgni onnét, hogy
system("echo >" pipe);
de akkor ez is elakad. Gondolom, rájön, hogy ez vagy ugyanaz a process, vagy annak gyermeke. Még csak tapogatózom, de nem értem a jelenséget egyelőre.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Igy viszont szepen megy:
x=0; while true; do echo $x; x=$((x+1)); sleep 1; done > /tmp/fifo
A masik terminalban, ezelott inditva:
apal@laptop:~$ awk 'BEGIN { while ( 1 ) { if ((getline row < "/tmp/fifo")>0 ) printf("[%s]\n",row); } }'
[0]
[1]
[2]
[3]
[4]
[5]
[6]
Szepen, masodpercenkent, ahogy jon.
- A hozzászóláshoz be kell jelentkezni
Na jó, de az első 0 megérkezése előtt a getline-ban vár szerintem nálad is. :(
Szerk.: bocs, nem. Akkor nálam van valami anomália.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Persze hogy var. Az fgets() is varna ilyenkor. Merthogy ez vsz egy fgets() :) De hogy van-e select()-analog az awk-ban az jo kerdes :)
- A hozzászóláshoz be kell jelentkezni
És akkor mi a megfejtés? :(
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
El tudom játszani ebből az awk scriptből, hogy nem én vagyok az, aki a fifo-ba ír? Tehát magamnak szeretnék írni. Ugye, ha a fifo-ba írok, az a másik irány. Azt szeretném, hogy a távoli végébe írjak egy newline-t, de ebből a scriptből, aztán majd örül neki a getline, hogy jött valami.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ilyesmire gondolsz mint print "valami" > /tmp/fifo?
- A hozzászóláshoz be kell jelentkezni
Igen, de rájöttem, ez nem megoldás, mert csak azért nem blokkolt, mert nem zártam le a pipe-ot. Szóval nem ttudom átverni.
Akkor az kellene, hogy valamivel meg tudjam vizsgálni, üres-e a pipe. Ha igen, kihagynám a getline-t, ha nem, akkor olvastatnék vele. Vagy akkor azzal, amivel az ürességet vizsgálom. Most erre tényleg C-ben kell programot írni? Vagy erre ott lesz nekem a socat parancs?
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Mit csinalna az awk amikor epp' nincs semmi a fifo-ban? Mert ez vagy nagyon busy wait, vagy async multiplex iranyvonal lehet igy elso ranezesre.
- A hozzászóláshoz be kell jelentkezni
Van egy zárt ciklusom. Amikor nincs semmi a fifoban, akkor socat-tal USB-re küldözget egy hardware-nek parancsokat, amelynek a válaszait feldolgozom, pontosabban gnuplottal oszcillogrammot rajzoltatok. Amikor beesik valami a fifo-ba, akkor a küldött parancsok közé kell merge-elni a fifoba érkezett parancsot. Ugye simán másik processből nem írhatok aszinkron az USB-re, mert az jó eséllyel épp foglalt, így szétesik a kommunikáció. Ezért szeretném ugyanazon processben intézni ezt akkor is, ha ezt az awk scriptet második példányban indítják el.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Most probaltam ilyesmiket:
mkfifo /tmp/fifo
exec 4<>/tmp/fifo
./nonblock 4
Ahol a ./nonblock egy faek egyszeru program ami az adott fd-t O_NONBLOCK-ra alltja. Majd:
awk 'BEGIN { while ( 1 ) { if ( (getline row < "/dev/fd/4")>0 ) { printf("[%s]\n",row); } else { print "no data"; system("sleep 1"); } } }'
De az strace alapjan vsz ez sem fog igy osszejonni. Ugyanis az awk szereti meghivogatni a close()-t, foleg azert mert igy akkor ugyan nem blokkol a getline, ellenben a mogotte levo read() EAGAIN-nel ter vissza. Szoval ja, az awk-t nem vszinu hogy erre talaltak ki :)
- A hozzászóláshoz be kell jelentkezni
Az awk-ban van close. Ha nem használod, akkor ezt általában az END (stdin és EOF esetén) vagy a kilépés intézi.
Érdemes lenne setlinebuf() kérdést is körüljárni, mivel a getline sort olvas.
- A hozzászóláshoz be kell jelentkezni
Az awk-ban van close. Ha nem használod, akkor ezt általában az END (stdin és EOF esetén) vagy a kilépés intézi.
Az strace alapjan nekem ugy tunt hogy a read() = -EAGAIN valtotta ki... persze lehet hogy beneztem, de ott volt egy hatarozott close(4) utana.
Érdemes lenne setlinebuf() kérdést is körüljárni, mivel a getline sort olvas.
Ez mi?
De barhogyis, ez szerintem ebben a formaban tulmutat az awk hataskoren. Mert a nonblock-ra bezarja az fd-t, a multipelxing pedig nem resze a nyelvnek. Olyasmit lehetne meg hogy van egy getline ciklus, es azt ket helyrol eteti a kollega: egyszer periodikusan a "routine operations" reszekent, egy masik process pedig kuldi az egyedi parancsokat. Csak ugye kerdes hogy mennyire keverednek ossze FIFO-ban a kulonbozo forrasok, van-e valami ami garantalja hogy sorbufferelt esetben azok nem mosodnak ossze.
- A hozzászóláshoz be kell jelentkezni
Vagy igy:
awk 'BEGIN { while ( 1 ) { while ( (getline row < "/tmp/fifo")>0 ) { printf("[%s]\n",row); } close("/tmp/fifo"); } }'
Vs:
x=0; while true; do echo $x > /tmp/fifo; x=$((x+1)); sleep 1; done
Ha bezarod a file-t amint elfogy, akkor mar a kovetkezo getline uj file-kent nyitja meg. Es akkor tudsz tobb echo ... > /tmp/fifo-val is operalni.
- A hozzászóláshoz be kell jelentkezni
Valamiért csak az elsőre vár, utána már nem ragad be a getline, legfeljebb nem >0-val tér vissza, de az nem baj.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
A fifoval én is szívtam. Végül megírtam 'C'-ben.
> Sol omnibus lucet.
- A hozzászóláshoz be kell jelentkezni
Amíg a kollégám ebédelt, kitaláltam egy workaround-ot. Nem pipe, hanem file lesz a megoldás. Úgyis tmpfs-en RAM-ban van, szóval gyors meg pici is, itt néhány tíz byte-okról beszélünk.
A ciklusomban:
if ((getline row <tempfile) > 0) {
printf("Ez jött: %s\n", row);
close(tempfile);
system("rm -f '" tempfile "'");
}
A külső program például:
echo 'Üzenet' >"$tempfile"
A tempfile értelemszerűen ugyanaz. És ez működik. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni