这个示例程序使用了 process
, async
, pipes
, 和 pipes-bytestring
包来执行一个外部命令,并在命令运行时将 stdout
和 stderr
分别写入不同的文件:
import Control.Applicative
import Control.Monad
import Control.Concurrent
import Control.Concurrent.Async
import Control.Exception
import Pipes
import qualified Pipes.ByteString as P
import Pipes.Concurrent
import System.Process
import System.IO
writeToFile :: Handle -> FilePath -> IO ()
writeToFile handle path =
finally (withFile path WriteMode $ \hOut ->
runEffect $ P.fromHandle handle >-> P.toHandle hOut)
(hClose handle)
main :: IO ()
main = do
(_,mOut,mErr,procHandle) <- createProcess $
(proc "foo" ["--help"]) { std_out = CreatePipe
, std_err = CreatePipe
}
let (hOut,hErr) = maybe (error "bogus handles")
id
((,) <$> mOut <*> mErr)
a1 <- async $ writeToFile hOut "stdout.txt"
a2 <- async $ writeToFile hErr "stderr.txt"
waitBoth a1 a2
return ()
以下是将stdout
和stderr
交错写入同一文件的变体:
writeToMailbox :: Handle -> Output ByteString -> IO ()
writeToMailbox handle oMailbox =
finally (runEffect $ P.fromHandle handle >-> toOutput oMailbox)
(hClose handle)
writeToFile :: Input ByteString -> FilePath -> IO ()
writeToFile iMailbox path =
withFile path WriteMode $ \hOut ->
runEffect $ fromInput iMailbox >-> P.toHandle hOut
main :: IO ()
main = do
(_,mOut,mErr,procHandle) <- createProcess $
(proc "foo" ["--help"]) { std_out = CreatePipe
, std_err = CreatePipe
}
let (hOut,hErr) = maybe (error "bogus handles")
id
((,) <$> mOut <*> mErr)
(mailBoxOut,mailBoxIn,seal) <- spawn' Unbounded
a1 <- async $ writeToMailbox hOut mailBoxOut
a2 <- async $ writeToMailbox hErr mailBoxOut
a3 <- async $ waitBoth a1 a2 >> atomically seal
writeToFile mailBoxIn "combined.txt"
wait a3
return ()
它使用
pipes-concurrent
。
每个句柄的线程都写入同一个邮箱。邮箱由主线程读取,同时在命令运行时编写输出文件。
seq
的原因是强制消耗程序的完整输出。否则(由于字符串是惰性的)可能会发生死锁:子进程将等待写入其输出,而主进程将等待进程完成。但是似乎serr
也可能存在同样的问题,我担心如果程序将大量输出写入其stderr,则上面的代码也可能会挂起。正确地执行这个可能并不是很简单,所以我可能更愿意寻找一些稳定的IO库来解决这个问题。 - Petrprocess
库有一个名为readProcessWithExitCode
的函数,它返回stdout
和stderr
作为字符串。但是,如果进程写了很多输出,如果您想在程序运行时访问输出,或者您希望stdout
和stderr
交错,那么这将不足够。 - danidiaz2>&1
。同时,将输出和错误流重定向到磁盘文件中也可以让我满意。 - Jan StolarekrunProcess
并将相同的句柄传递给 stdout 和 stderr(而不是Nothing
),它应该像2>&1
一样工作。 - hammar