Looking for usage examples of what's in System.Process
, I landed at this page.
Here's an excerpt of the code I found there:
import System.IO
import System.Process
main = do
(Just hin, Just hout, _, _) <- createProcess (proc "grep" ["hello"])
{ std_in = CreatePipe, std_out = CreatePipe }
hPutStr hin "hello grep\ngoodbye grep"
grepBytes <- hGetContents hout
putStrLn "> grep hello"
putStrLn grepBytes
I don't really understand why the execution blocks at the last line (indeed, if I change it to putStrLn "1" >> putStrLn grepBytes >> putStrLn "2"
, only 1
is printed). The code looks like I would have expected, so I'm a bit puzzled. Any clue?
Execution blocks because grep blocks, and grep blocks because execution blocks. Whoops!
grep reads to the end of its file (even if that file is stdin
). Since you haven't closed hin
, grep can never be sure whether you were intending to send more later or not. A similar commentary applies to hGetContents
: it reads to the end of its file, and since grep never ends its file, it can never be sure whether grep intended to output more later or not.
Toss an hClose hin
anywhere after your hPutStr
but before the use of grepBytes
to tell grep you're done. Then grep will return the favor and let hGetContents
know it's done.
You may ask: how come it worked for the other fellow? Well, I can't be sure, since I can't reproduce it. But one thing that could have happened is this: because hin
is not mentioned after the hPutStr
, it becomes garbage at that point, and when GHC collects it, it will graciously close it for you first if you forgot. So perhaps for the other fellow, garbage collection ran between the hPutStr
and the use of grepBytes
, closing hin
as is needed. I would definitely say it is good practice not to rely on this behavior, and hClose
each handle when you know you're done with it. (Corollary: don't use hGetContents
, which also delays hClose
to an undisclosed future time.)