这应该是一个简单的问题,但是到目前为止,我还没有找到任何直接的答案:如何使用Haskell进程忽略stderr
(或stdout
) process
库?例如,假设我有以下内容:
let proc = (shell "dir /z") {
std_in = UseHandle stdin
, std_out = CreatePipe
}
(_, out, _, rProc) <- createProcess Proc
exitCode <- waitForProcess rProc
(旁注:在Windows中,我确实知道dir
没有/z
开关。这就是我选择它的原因-因此我可以在stderr
上获得一些有趣的输出)
这样做只会导致stderr
被打印到控制台。现在,假设我想忽略stderr
。我该怎么做?
我发现的唯一线索是在process
文档的this part中:
NoStream
关闭流的文件描述符,而不传递句柄。在POSIX系统上,这可能导致子进程中的异常行为,因为在关闭文件后尝试读取或写入会引发错误。仅应将其用于完全不使用文件描述符的子进程。如果您希望忽略子进程的输出,则应该创建一个管道并手动将其清空,或者传递一个写入Handle
的{{1}}。
这在一定程度上有所帮助,但仍然存在一些未解决的问题。在非POSIX系统上,可以使用/dev/null
吗?它是指先创建一个管道然后将其排干,但我找不到有关如何执行此操作的任何信息? Windows上的NoStream
是/dev/null
,除非您使用的是MSYS或Cygwin,否则(我认为)又是NUL
,所以我想避免这种情况。
因此,我再次提出一个问题:忽略操作系统的/dev/null
的,与操作系统无关的推荐方法是什么?
答案 0 :(得分:2)
答案 1 :(得分:0)
这是一种正确的方法:
import Control.Concurrent
import Control.Exception
import System.IO
import System.Process
forceGetContents :: String -> IO ()
forceGetContents s = evaluate (length s) >> return ()
main = do
outMVar <- newEmptyMVar
let proc = (shell "dir /z") {
std_in = UseHandle stdin
, std_out = CreatePipe
, std_err = CreatePipe
}
(_, Just out, Just err, rProc) <- createProcess proc
forkIO (hGetContents err >>= forceGetContents)
forkIO $ do
s <- hGetContents out
forceGetContents s
putMVar outMVar s
exitCode <- waitForProcess rProc
outContents <- takeMVar outMVar
putStr outContents -- or whatever
一些关于删除答案的注释中值得注意的事情:
waitForProcess
,则应派生一个线程以排空输出管道。否则,它可能会在可以打印所需的所有内容之前被杀死,从而产生不完整的输出。forceGetContents
是强制String
返回的hGetContents
的完整方法的一种好方法,但是其他String
生产者可能需要更多的参与强制功能。另请参见rnf
软件包中的deepseq
。如果存在您知道该过程将遵循的协议,则可以同时解决(2)和(3)的问题,即在完成输出后将知道该协议。然后,您可以流式传输输出(减少可能被提前丢弃的位的内存压力),并可以延迟waitForProcess
直到知道输出完成为止(避免需要派生线程来耗尽输出-尽管仍然需要错误的分叉线程!)。