忽略进程的标准错误
Ignoring stderr of process
这应该是一个简单的问题,但到目前为止我还没有找到任何直接的答案:how does one ignore the stderr
(or stdout
) of使用 process
库 的 Haskell 进程?例如,假设我有以下内容:
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
Close the stream's file descriptor without passing a Handle. On POSIX systems this may lead to strange behavior in the child process because attempting to read or write after the file has been closed throws an error. This should only be used with child processes that don't use the file descriptor at all. If you wish to ignore the child process's output you should either create a pipe and drain it manually or pass a Handle
that writes to /dev/null
.
这有点帮助,但仍有一些问题没有得到解答。在非 POSIX 系统上,可以使用 NoStream
吗?它指的是创建一个管道然后将其排出,但我找不到任何关于如何做到这一点的信息? /dev/null
在 Windows 上是 NUL
,除非你使用 MSYS 或 Cygwin,当它又是 /dev/null
时(我认为)——所以我想避免这种情况。
所以重申我的问题:推荐的 OS 忽略进程的 stderr
不可知的方法是什么?
我想 nullStream
in typed-process package 就是您要找的。
这是一种正确的方法:
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
,你应该fork一个线程来排空输出管道。否则它可能会在打印它想要的所有内容之前被杀死,从而给出不完整的输出。
- 这会将整个过程的输出(尽管不是错误流的全部内容)存储在内存中。这可能非常昂贵。
forceGetContents
是强制对 hGetContents
返回的 String
进行全面评估的好方法,但还有其他 String
-生产者可能需要更多涉及强制功能。另请参阅 deepseq
包中的 rnf
。
如果有一个您知道流程将遵循的协议,您可以同时解决 (2) 和 (3),您将知道何时完成输出。然后你可以流式输出(减少可以提前丢弃的位的内存压力),并且可以延迟 waitForProcess
直到你知道它完成输出(避免需要分叉一个线程来耗尽输出 - 虽然仍然需要一个分支线程来解决错误!)。
这应该是一个简单的问题,但到目前为止我还没有找到任何直接的答案:how does one ignore the stderr
(or stdout
) of使用 process
库 的 Haskell 进程?例如,假设我有以下内容:
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
Close the stream's file descriptor without passing a Handle. On POSIX systems this may lead to strange behavior in the child process because attempting to read or write after the file has been closed throws an error. This should only be used with child processes that don't use the file descriptor at all. If you wish to ignore the child process's output you should either create a pipe and drain it manually or pass aHandle
that writes to/dev/null
.
这有点帮助,但仍有一些问题没有得到解答。在非 POSIX 系统上,可以使用 NoStream
吗?它指的是创建一个管道然后将其排出,但我找不到任何关于如何做到这一点的信息? /dev/null
在 Windows 上是 NUL
,除非你使用 MSYS 或 Cygwin,当它又是 /dev/null
时(我认为)——所以我想避免这种情况。
所以重申我的问题:推荐的 OS 忽略进程的 stderr
不可知的方法是什么?
我想 nullStream
in typed-process package 就是您要找的。
这是一种正确的方法:
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
,你应该fork一个线程来排空输出管道。否则它可能会在打印它想要的所有内容之前被杀死,从而给出不完整的输出。 - 这会将整个过程的输出(尽管不是错误流的全部内容)存储在内存中。这可能非常昂贵。
forceGetContents
是强制对hGetContents
返回的String
进行全面评估的好方法,但还有其他String
-生产者可能需要更多涉及强制功能。另请参阅deepseq
包中的rnf
。
如果有一个您知道流程将遵循的协议,您可以同时解决 (2) 和 (3),您将知道何时完成输出。然后你可以流式输出(减少可以提前丢弃的位的内存压力),并且可以延迟 waitForProcess
直到你知道它完成输出(避免需要分叉一个线程来耗尽输出 - 虽然仍然需要一个分支线程来解决错误!)。