【问题标题】:How can I combine Handles in Haskell?如何在 Haskell 中组合句柄?
【发布时间】:2011-10-07 21:13:57
【问题描述】:

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

createProcess 提供的灵活性一开始似乎很有希望:可以指定一个Handle 用于标准文件描述符,因此可以为stdoutstderr 指定相同的Handle。但是,Handle 参数必须在调用之前已经存在。如果无法在调用函数之前凭空创建Handle,我不确定问题是否可以通过这种方式解决。

编辑:解决方案需要在任何平台上都能正常工作。

【问题讨论】:

  • 您需要跨平台的方法吗?还是仅在 unix-y 系统上运行?
  • @camccann 是的;相应地更新了问题。
  • 好吧,here's the answer you would have gotten 否则。从技术上讲,如果你有一个像 cygwin 这样的兼容层,这是可行的,但那是……呃。
  • 确实。我目前正在开发一个使用这些东西的系统,这个问题的动机是我可以转向一种更便携的方法。

标签: haskell io subprocess


【解决方案1】:

来自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

【讨论】:

  • 太棒了!我可能因为 GHC 特定的库而错过了这个
【解决方案2】:

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

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

导出c_pipeSystem.Posix.Internals 模块默认是隐藏的,但您可以编译一个自定义版本的base 来访问它(提示:使用cabal-dev)。或者,您可以通过 FFI 访问pipe注意:此解决方案是特定于 GHC 的。

【讨论】:

  • 这似乎是它应该实现的方式,谢谢。我将试验一下这种方法的可移植性。
  • @acfoltzer 你能告诉我们你的结果吗?
  • @nh2 遗憾的是,我们在 bash 解决方案中一瘸一拐。不过,在某个时候重新审视这个会很好
【解决方案3】:

掌握Handle 并不难:System.IO 提供常量stdin,stdout,stderr :: Handle 和函数withFile :: FilePath -&gt; IOMode -&gt; (Handle -&gt; IO r) -&gt; IO ropenFile :: FilePath -&gt; IOMode -&gt; IO Handle

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2020-01-06
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多