[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
-George
More information about the Haskell-Cafe
mailing list