如何在Haskell中组合Handles?

时间:2011-07-18 17:27:14

标签: haskell io subprocess

我想在Haskell中使用bash的2>&1重定向,将stdoutstderr从一个进程合并为一个Handle。使用System.Process.createProcess或类似的库函数直接执行此操作会很好,特别是如果它使用与bash重定向w.r.t相同的语义。交错来自句柄的输入。

createProcess提供的灵活性最初似乎很有希望:可以指定Handle用于标准文件描述符,因此可以为{{1}提供相同的Handle }和stdout。但是,stderr参数必须在调用之前已存在。如果没有能力在调用函数之前从空中创建Handle,我不确定问题是否可以通过这种方式解决。

编辑:无论平台如何,解决方案都需要运作。

3 个答案:

答案 0 :(得分:4)

开始使用Handle并不太难:System.IO提供常量stdin,stdout,stderr :: Handle和功能withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r以及openFile :: FilePath -> IOMode -> IO Handle

或者,您可以从createProcess请求新的管道并将自己设置为转发服务(从您孩子的新stdoutstderr句柄中读取并将其发送到您的任何地方等)。

答案 1 :(得分:3)

来自here

import GHC.IO.Handle   -- yes, it's GHC-specific
import System.IO

main = do
  stdout_excl <- hDuplicate stdout
  hDuplicateTo stderr stdout  -- redirect stdout to stderr

  putStrLn "Hello stderr" -- will print to stderr
  hPutStrLn stdout_excl "Hello stdout" -- prints to stdout

答案 2 :(得分:2)

由于Windows本身支持pipe (3)和GHC的IO库uses CRT file descriptors internally on Windows,因此有可能提出一种至少适用于Windows和* nix的解决方案。基本算法是:

  • 致电pipe。这为您提供了两个文件描述符,您可以使用fdToHandle'将其转换为Handles
  • 调用createProcessstdoutstderr都设置为管道的写入结束。
  • 从管道的读取端读取子输出。

导出c_pipe的{​​{3}}模块默认是隐藏的,但您可以编译允许您访问它的base自定义版本(提示:使用System.Posix.Internals })。或者,您可以通过FFI访问pipe NB:此解决方案是GHC特定的。