Article 6829 of comp.lang.perl: Xref: feenix.metronet.com comp.lang.perl:6829 Path: feenix.metronet.com!news.ecn.bgu.edu!usenet.ins.cwru.edu!howland.reston.ans.net!europa.eng.gtefsd.com!uunet!olivea!pagesat!news.cerf.net!software.com!not-for-mail From: mike@software.com (Michael D'Errico) Newsgroups: comp.lang.perl Subject: Connecting to STDIN/STDOUT of another program (was "Redirecting I/O") Date: 14 Oct 1993 19:58:46 -0700 Organization: Software Now, Santa Barbara, CA Lines: 123 Distribution: world Message-ID: <29l3l6$sku@rome.software.com> References: <29j8i7INNpqn@dapsun.lif.icnet.uk> NNTP-Posting-Host: rome.software.com Keywords: STDIN STDOUT pipe alex@bison.lif.icnet.uk (Alex Whittaker - BIU) writes: > The good book > (Nutshell) says "You may not have an open command that pipes both in and > out, though it's easy to build one using the pipe and fork commands). > Well, I guess you know why I am here now, how do I both read and write to > a program, Below is a script that does this. It creates two pipes for communication between the Perl script and the external program, then forks and execs the external program with the pipes attached to STDIN/STDOUT. The perl script also creates the filehandles KEYBOARD and TERMINAL which do the obvious. You can then issue commands to the program via STDOUT, and read the responses from STDIN. User inputs are read from KEYBOARD and outputs are displayed to TERMINAL. Here is a simple diagram of the inter-process communication: ______ \||/_ ______ STDOUT STDIN ______ TERMINAL |I coul| oo \ | |---------[pipe]------>>>| |---------------->>>|dn't r| L_ | Your | | Perl | |esist!| \/ | Prog | STDIN STDOUT | | KEYBOARD ________ | |______|<<<------[pipe]---------|______|<<<---------------[========] / ---OOO- |ooooooo| > and what are the dangers darkly hinted at. You may need to setup the read to be non-blocking, or your script may hang indefinitely. Look into using sysread if you have problems with buffering. Michael D'Errico mike@software.com ============================================================================ #!/usr/bin/perl ##### program you want to run $program_name = "command name goes here"; $program_args = "command-line arguments go here"; ##################################################################### ##### only need to modify below where it says the script starts ##### ##################################################################### ##### create pipes to handle communication pipe (FROM_PERL, TO_PROGRAM); pipe (FROM_PROGRAM, TO_PERL); ##### create a child process $pid = fork; die "Couldn't fork: $!" unless defined $pid; ##### child process becomes the program if ($pid == 0) { ##### attach standard input/output/error to the pipes close STDIN; open (STDIN, '<&FROM_PERL') || die ("open: $!"); close STDOUT; open (STDOUT, '>&TO_PERL') || die ("open: $!"); close STDERR; open (STDERR, '>&STDOUT') || die; ##### close unused parts of pipes close FROM_PROGRAM; close TO_PROGRAM; ##### unbuffer the outputs select STDERR; $| = 1; select STDOUT; $| = 1; ##### execute the program exec $program_name split (' ', $program_name, $program_args); ##### shouldn't get here!!! die; } ##### parent process is the perl script open (TERMINAL, '>&STDOUT'); open (KEYBOARD, '<&STDIN'); close STDIN; open (STDIN, '<&FROM_PROGRAM') || die ("open: $!"); close STDOUT; open (STDOUT, '>&TO_PROGRAM') || die ("open: $!"); close FROM_PERL; close TO_PERL; ##### unbuffer all the outputs select TERMINAL; $| = 1; select STDERR; $| = 1; select STDOUT; $| = 1; ##################################################################### ####################### Script Starts Here ######################## ##################################################################### ##### This is just an example of what you can do.... print TERMINAL "Enter a command: "; while () { last if /quit/; # stop when 'quit' is entered print; # send keyboard input to the program $reply = ; # get (first line of) reply from program chop $reply; # remove trailing "\n" character print TERMINAL "Response: \"$reply\"\n\n"; print TERMINAL "Enter a command: "; } print TERMINAL "\nDone.\n"; kill $pid; exit;