
Hi, I'm trying to understand how to get pipes working in Haskell, in particular with the revamped System.Process (though I've tried similar experiments with System.Posix.IO and Control.Concurrent). Specifically I'm trying to concatenate the output of two system calls into the input of a third. The following code does not get the job done:
import Data.Maybe ( fromJust ) import System.IO import System.Process
sink :: String -> IO (Handle,ProcessHandle) sink s = do let p = (shell s) { std_in = CreatePipe } (mh, _, _, ph) <- createProcess p return (fromJust mh,ph)
source :: String -> Handle -> IO () source s h = do let p = (shell s) { std_out = UseHandle h, close_fds = False } (_, _, _, ph) <- createProcess p waitForProcess ph return ()
main :: IO () main = do (h,p) <- sink "sort" source "df" h source "df -h" h waitForProcess p return ()
When I run this, I see that the filehandle h is closed after the first df, so the output only has one of the two df's included in it. I tried also System.Posix.IO (createPipe, fdToHandle, dup) to make this work, but that gave a "read failed" error. Is there any way to get this done...? In general, given a handful of system calls (and/or read/write handles), is there a way to combine them all together? (I also tried using forkIO on my own function pipe :: [Handle] -> Handle -> IO (), which does what you'd expect given multiple read handles and a single write handle, but couldn't get any output from that at all...) Any help is appreciated, steve

On 2008 Oct 19, at 1:37, Stephen Hicks wrote:
I'm trying to understand how to get pipes working in Haskell, in particular with the revamped System.Process (though I've tried similar experiments with System.Posix.IO and Control.Concurrent). Specifically I'm trying to concatenate the output of two system calls into the input of a third. The following code does not get the job done:
Pipes are perhaps a bit misnamed: if you want to combine the output of two pipes and funnel it into a third you can't simply "plumb them together", you need to provide code which reads from the output pipes and writes into the input pipe. If you don't care about order, forkIO a thread for each output pipe which reads from the output pipe it's passed and writes to the input pipe. If order is significant, use mapM/forM to run the output-to-input code on each handle in turn. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

Brandon S. Allbery KF8NH wrote:
Pipes are perhaps a bit misnamed: if you want to combine the output of two pipes and funnel it into a third you can't simply "plumb them together", you need to provide code which reads from the output pipes and writes into the input pipe.
With the new System.Process in 6.10, that's not the case. If you're building a pipeline "a | b | c | d" you only need to write into "a" and read from "d", System.Process handles everything in between.

Matti Niemenmaa wrote:
Brandon S. Allbery KF8NH wrote:
Pipes are perhaps a bit misnamed: if you want to combine the output of two pipes and funnel it into a third you can't simply "plumb them together", you need to provide code which reads from the output pipes and writes into the input pipe.
With the new System.Process in 6.10, that's not the case. If you're building a pipeline "a | b | c | d" you only need to write into "a" and read from "d", System.Process handles everything in between.
Ack, sorry for the spam, I misunderstood: my second statement holds but it's irrelevant to the topic, which was having "a" and "b" both go straight into a "c".

Hackage has the pipe library and the shell-pipe library. The package
page for shell-pipe says it's probably to use system.Process now, but
pipe was recently hackagized, by another person on this thread
actually, I believe (Matti).
Once you solve this problem, perhaps your solution could be patched
into the Pipe package.
2008/10/19 Stephen Hicks
Hi,
I'm trying to understand how to get pipes working in Haskell, in particular with the revamped System.Process (though I've tried similar experiments with System.Posix.IO and Control.Concurrent). Specifically I'm trying to concatenate the output of two system calls into the input of a third. The following code does not get the job done:
import Data.Maybe ( fromJust ) import System.IO import System.Process
sink :: String -> IO (Handle,ProcessHandle) sink s = do let p = (shell s) { std_in = CreatePipe } (mh, _, _, ph) <- createProcess p return (fromJust mh,ph)
source :: String -> Handle -> IO () source s h = do let p = (shell s) { std_out = UseHandle h, close_fds = False } (_, _, _, ph) <- createProcess p waitForProcess ph return ()
main :: IO () main = do (h,p) <- sink "sort" source "df" h source "df -h" h waitForProcess p return ()
When I run this, I see that the filehandle h is closed after the first df, so the output only has one of the two df's included in it. I tried also System.Posix.IO (createPipe, fdToHandle, dup) to make this work, but that gave a "read failed" error. Is there any way to get this done...? In general, given a handful of system calls (and/or read/write handles), is there a way to combine them all together? (I also tried using forkIO on my own function pipe :: [Handle] -> Handle -> IO (), which does what you'd expect given multiple read handles and a single write handle, but couldn't get any output from that at all...)
Any help is appreciated, steve _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (4)
-
Brandon S. Allbery KF8NH
-
Matti Niemenmaa
-
Stephen Hicks
-
Thomas Hartman