[Shell] Bidirectionele pipe tussen twee programma's

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 13:10
Ik vroeg me af wat de beste manier is om een bidirectionele pipe tussen twee programma's tot stand te brengen. Daarbij is het dus de bedoeling dat de standard output van het eerste programma aan de standard input van het tweede wordt gekoppeld, en vice versa.

Het beste wat ik heb kunnen verzinnen is gebruik te maken van bash' ondersteuning voor coprocessen:
coproc foo && bar <&${COPROC[0]}- >&${COPROC[1]}-

Ik vraag me echter af of er een nog eenvoudigere manier is, die misschien ook meer portable is. Ik heb er op StackOverflow wel deze vraag over gevonden, maar daar worden eigenlijk alleen maar lelijkere oplossingen met fifo's e.d. voorgesteld.

Acties:
  • 0 Henk 'm!

  • Sir Isaac
  • Registratie: September 2002
  • Laatst online: 21-05 20:45
Ik heb zelf in het verleden naar andere manieren gekeken om via een dubbelzijdig pipe een ander programma aan te sturen, maar dat wordt erg afgeraden. De kans bestaat dat beide programma's op input gaan wachten bijvoorbeeld omdat data in een buffer blijft hangen.
Als je inderdaad een programma vanuit een ander programma wilt besturen zou ik naar expect (of pexpect) kijken.

[ Voor 17% gewijzigd door Sir Isaac op 06-09-2010 09:38 ]


Acties:
  • 0 Henk 'm!

  • Elijan9
  • Registratie: Februari 2004
  • Laatst online: 10-09 21:08
Ik ben het er niet mee eens dat de Stackoverflow antwoorden "lelijker' zijn. Met name deze vind ik echt niet lelijk:
Bash:
1
2
3
mkfifo foo
A < foo | B > foo
rm foo


Eerlijk gezegd vind ik het concept programma A schrijft via stdout naar B schrijft via stdout naar A op zich al lelijk :/
Als het dan toch moet, zou ik liever gebruik maken van een parent proces die de stdout/stdin voor beide processen op een goede manier regelt/doorschuift... Liever zou ik communiceren tussen de processen met sockets.

[ Voor 10% gewijzigd door Elijan9 op 06-09-2010 15:01 ]

War is when the young and stupid are tricked by the old and bitter into killing each other. - Niko Bellic


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 13:10
Sir Isaac schreef op maandag 06 september 2010 @ 09:38:
Ik heb zelf in het verleden naar andere manieren gekeken om via een dubbelzijdig pipe een ander programma aan te sturen, maar dat wordt erg afgeraden. De kans bestaat dat beide programma's op input gaan wachten bijvoorbeeld omdat data in een buffer blijft hangen.
Mee eens, maar in dit geval gaat het om een interactieve applicatie die ik met behulp van netcat naar een netwerkservice wil laten verbinden. Als het programma vast zou lopen duw ik zelf op control-c. Dan lijkt expect me overkill, want ik hoef geen echte automation.
Elijan9 schreef op maandag 06 september 2010 @ 15:00:
Ik ben het er niet mee eens dat de Stackoverflow antwoorden "lelijker' zijn. Met name deze vind ik echt niet lelijk: [knip: fifo]
Wat ik daar jammer aan vind is dat je write support in de cwd nodig hebt, en filesystem support voor fifo's, alleen om twee processen te laten communiceren. Verder is het probleem met het handmatig maken van een file dat je ten eerste je script niet twee keer tegelijk kunt runnen (kun je weer omheen hacken door het process id van de shell in de filename te verwerken) en als je je scriptje control-c't je fifo niet verwijderd wordt (kun je fixen met een trap) maar als je dat allemaal toe moet voegen wordt het i.m.o. een stuk complexer

Dan vind ik persoonlijk het coproces mooier omdat tenminste alles binnen bash gebeurt, je geen tijdelijke files nodig hebt, en je buiten bash geen noemenswaardige dependencies hebt op je omgeving.
Eerlijk gezegd vind ik het concept programma A schrijft via stdout naar B schrijft via stdout naar A op zich al lelijk
Hoe stel je dan voor dat ik een programma aan een TCP socket koppel? (Een soort reverse inetd als 't ware...) Ik sta open voor suggesties. :)

[ Voor 6% gewijzigd door Soultaker op 06-09-2010 15:57 ]


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

iets als:

code:
1
2
3
4
netcat ... &
PID=$!

process < /proc/$PID/fd/4 > /proc/$PID/fd/4


Kun je zo niet aan de FD's geraken ?

Of iets als dit:
http://thesmithfam.org/bl...rogramming-with-devtcp-2/

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • deadinspace
  • Registratie: Juni 2001
  • Laatst online: 05-09 17:21

deadinspace

The what goes where now?

Soultaker schreef op maandag 06 september 2010 @ 15:56:
Mee eens, maar in dit geval gaat het om een interactieve applicatie die ik met behulp van netcat naar een netwerkservice wil laten verbinden.
Ah, dat is de use case... Ik vroeg me al af waarvoor je dit wilde :P

Ik zou eens naar socket kijken ipv netcat, die kan een programma starten en de stdio daarvan aan zichzelf koppelen.

Merk wel op dat dit (net als pipe/fifo oplossingen) niet altijd goed werkt met interactieve programma's ivm buffering. Vergelijk bij socket bijvoorbeeld eens "grep bla" en "grep --line-buffered bla" als commando.
Wat ik daar jammer aan vind is dat je write support in de cwd nodig hebt
Niet noodzakelijk de cwd natuurlijk, je zou ook /tmp kunnen gebruiken.
Verder is het probleem met het handmatig maken van een file dat je ten eerste je script niet twee keer tegelijk kunt runnen (kun je weer omheen hacken door het process id van de shell in de filename te verwerken)
Of natuurlijk netjes met mktemp ;)

Acties:
  • 0 Henk 'm!

  • Elijan9
  • Registratie: Februari 2004
  • Laatst online: 10-09 21:08
Nou, eerlijk gezegd ben ik heel snel geneigd dit gewoon vanuit Python te doen en dan de twee processen via de subprocess module uitvoeren en deze op de juiste manier aan elkaar knopen. Dan kan je m.i. ook beter de opstart/afsluit volgorde bepalen, slim uitvoer en signals afhandelen, enzovoort. Ook kan je net gemakkelijk anticiperen op stderr uitvoer.

Maar als het zou willen koppelen via een socket, dan zou ik daarvoor gewoon twee commandline/configuratie opties aan beide programma's toevoegen als dat dynamisch moet...


.edit: Overigens is het waarschijnlijk zo dat de ene applicatie de slave is van de ander, dan zou ik vanuit de master applicatie het slave proces uitvoeren en data afvangen/invoeren.

[ Voor 15% gewijzigd door Elijan9 op 06-09-2010 16:47 ]

War is when the young and stupid are tricked by the old and bitter into killing each other. - Niko Bellic


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 13:10
H!GHGuY schreef op maandag 06 september 2010 @ 16:06:
code:
1
2
3
netcat ... &
PID=$!
process < /proc/$PID/fd/4 > /proc/$PID/fd/4

Kun je zo niet aan de FD's geraken ?
Ik zou denken van wel maar ik krijg het niet werkend en ik weet niet waarom. :/
Nice, dat is een mooie suggestie! Ook bash-specifiek, maar dan zonder afhankelijk te zijn van nc. Ik kan het in mijn geval zelfs versimpelen tot:
app <>/dev/tcp/$host/$port >&0
deadinspace schreef op maandag 06 september 2010 @ 16:39:
Ik zou eens naar socket kijken ipv netcat, die kan een programma starten en de stdio daarvan aan zichzelf koppelen.
Ik ken socket niet (heb je daar een linkje bij? het is nogal een vervelende zoekterm) en mijn Gentoo-gepatchte versie van netcat kan dat ook, maar die had als nadeel dat dan ook stderr over de socket verstuurd werd en dat was nu precies niet de bedoeling.
Merk wel op dat dit (net als pipe/fifo oplossingen) niet altijd goed werkt met interactieve programma's ivm buffering.
Goed punt, maar in dit geval heb ik het programma zelf geschreven dus zorg ik ervoor dat ik m'n uitvoer waar nodig flush. Het programma is ook bedoeld om via een pipe te draaien, dus flushen was hier toch al een vereiste.

Acties:
  • 0 Henk 'm!

  • deadinspace
  • Registratie: Juni 2001
  • Laatst online: 05-09 17:21

deadinspace

The what goes where now?

Soultaker schreef op maandag 06 september 2010 @ 18:11:
Ik ken socket niet (heb je daar een linkje bij? het is nogal een vervelende zoekterm) en mijn Gentoo-gepatchte versie van netcat kan dat ook, maar die had als nadeel dat dan ook stderr over de socket verstuurd werd en dat was nu precies niet de bedoeling.
http://www.jnickelsen.de/socket/

Socket koppelt ook stderr aan de TCP socket, maar dat is denk ik wel te omzeilen door "programma 2> /dev/null" als commando op te geven.
Goed punt, maar in dit geval heb ik het programma zelf geschreven dus zorg ik ervoor dat ik m'n uitvoer waar nodig flush. Het programma is ook bedoeld om via een pipe te draaien, dus flushen was hier toch al een vereiste.
Ah ok. In plaats van overal expliciet te flushen zou je ook kunnen overwegen stdout op unbuffered te zetten met setbuf(3) of een van zijn vriendjes.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 13:10
deadinspace schreef op maandag 06 september 2010 @ 18:47:
http://www.jnickelsen.de/socket/
[..]
Socket koppelt ook stderr aan de TCP socket, maar dat is denk ik wel te omzeilen door "programma 2> /dev/null" als commando op te geven.
Ah, feitelijk een soort netcat clone dus (maar minder crappy). Ik wilde eigenlijk de stderr naar de terminal sturen, dus dan moet de redirection wat ingewikkelder. Ik zag trouwens ook dat nmap ook een netcat clone heeft (ncat) die wél precies doet wat ik wil (stderr ongemoeid laten). Dat is dus eigenlijk de ideale tool for the job, maar stiekem vind ik de bash-oplossing met /dev/tcp wel gaaf.
In plaats van overal expliciet te flushen zou je ook kunnen overwegen stdout op unbuffered te zetten met setbuf(3) of een van zijn vriendjes.
Klopt, maar we gaan nu wel heel erg off-topic. :+

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 13:10
Ik denk dat we alle mogelijkheden wel zo'n beetje besproken hebben nu. Iedereen bedankt voor de reacties! Ik heb er een aantal nieuwe dingen van geleerd. :)
Pagina: 1