[Haskell-cafe] Re: Trouble with simple embedding of shell in haskell

George Brewster g at brewster.org
Thu Sep 21 21:33:37 EDT 2006

Donn Cave wrote:
> On Thu, 21 Sep 2006, George Brewster wrote:
>>I'm just tried writing a function to allow convenient embedding of shell
>>commands, but I'm running into behavior I don't really understand 
>>somewhere at the intersection of lazy evaluation, IO, and threading.
> You may also find some unwelcome surprises in the area of pipes and
> buffered I/O, that aren't specifically about Haskell.  Are you on a
> UNIX platform?
> I "rewrote" your function by removing both instances of forkIO, and
> it worked about like I expected.  (The last one encounters an error
> "broken pipe" when it tries to write "there" to the "echo hi" shell
> process, because that process exits instead of reading from its input.)
> I can't say whether you really need forkIO, or whether it's really going
> to do what you need - not only do I not know enough about the thread
> model, neither do I know what you're really trying to do.
> 	Donn Cave, donn at drizzle.com

Yup, I'm on linux. My goal is to have a function which gives me a lazy 
string which is the output of a shell command, and takes a string as 
input. In particular, I'd like the shell command to behave lazily (read 
only as much input as is needed, and write only as much output as 
needed), so things like this work (should terminate and print a few 
lines of "hi"):

main = sh "yes hi" "there" >>= sh "head" >>= putStrLn

I tried your suggestion out (remove forkIO), and when I do that, this 
example returns but doesn't print anything. Interestingly, my original 
implementation usually behaves this way also, but occasionally works as 
I would like. I had forked a seperate thread for writing the input 
string to the command so that the writing wouldn't block if the process 
filled up its write buffer and read buffer before we were done writing 
the string to it -- this doesn't seem to really have worked for me though.

For reference, here is the funciton in question:

sh :: String -> String -> IO String
sh cmd = \input ->
          do (stdin, stdout, _, pid) <- runInteractiveCommand cmd
             forkIO $ hPutStr stdin input >> hClose stdin
             forkIO $ waitForProcess pid >> return ()
             hGetContents stdout


More information about the Haskell-Cafe mailing list