忽略标准错误

时间:2019-07-11 00:03:12

标签: haskell process stderr

这应该是一个简单的问题,但是到目前为止,我还没有找到任何直接的答案:如何使用Haskell进程忽略stderr(或stdoutprocess?例如,假设我有以下内容:

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的,与操作系统无关的推荐方法是什么?

2 个答案:

答案 0 :(得分:2)

我猜您正在寻找nullStream in typed-process package

答案 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

一些关于删除答案的注释中值得注意的事情:

  1. 您应该分叉一个螺纹以排空错误管道。否则,如果有很多错误,则开始的进程可能会被杀死,然后才能打印所有错误,从而导致混乱的调试会话。
  2. 如果您要转到waitForProcess,则应派生一个线程以排空输出管道。否则,它可能会在可以打印所需的所有内容之前被杀死,从而产生不完整的输出。
  3. 这会将进程的整个输出(尽管不是错误流的全部内容)存储在内存中。这可能会很昂贵。
  4. forceGetContents是强制String返回的hGetContents的完整方法的一种好方法,但是其他String生产者可能需要更多的参与强制功能。另请参见rnf软件包中的deepseq

如果存在您知道该过程将遵循的协议,则可以同时解决(2)和(3)的问题,即在完成输出后将知道该协议。然后,您可以流式传输输出(减少可能被提前丢弃的位的内存压力),并可以延迟waitForProcess直到知道输出完成为止(避免需要派生线程来耗尽输出-尽管仍然需要错误的分叉线程!)。