读取使用 createProcess 获得的管道的几行,然后将其关闭
Posted
技术标签:
【中文标题】读取使用 createProcess 获得的管道的几行,然后将其关闭【英文标题】:Reading a couple of lines of a pipe obtained with createProcess and then closing it 【发布时间】:2017-11-01 13:25:22 【问题描述】:我有一个产生如下进程的函数:
(_, Just outh, _, ph) <- createProcess $
(proc "someproc" []) std_out = CreatePipe
line <- hGetLine outh
doSomeComputationOn line
-- ... 'outh' is not read anymore from here onwards
所以"someproc"
被创建,然后父级从它读取一个line
获取一些信息,然后它忘记了句柄为outh
的管道。
现在的问题是,如果管道没有被读取,"someproc"
一满就会阻塞。所以这要求父进程读取outh
,即使它不做任何事情。所以我的问题是:
-
这是获取子进程输出的第一行然后忘记其他输出的好方法吗?
Haskell 中是否有任何方法可以自动丢弃管道的输入(甚至将其重定向到文件)?
到目前为止,我能看到解决此问题的唯一方法是生成一个新线程,该线程不断尝试从 outh
读取(并丢弃输出),这表明我做错了什么......
作为附加背景,这个问题与this one有关。
【问题讨论】:
【参考方案1】:现在的问题是,如果管道没有被读取,“someproc”一满就会阻塞。 [...] Haskell 有什么方法可以自动丢弃 输入到管道(甚至重定向到文件)?
process 有一个帮助程序库,名为 process-streaming(由本答案的作者编写),它试图做到这一点:即使用户传递了一个不t 耗尽标准流,它会在引擎盖下自动耗尽流以避免潜在的死锁。
该库不直接使用句柄,但接受 pipe 消耗函数和 foldl 通过 adapter type 折叠。
读取第一行的例子:
import Data.Text.Lazy
import qualified Pipes.Prelude
import System.Process.Streaming (CreateProcess,shell,
piped,execute,foldOut,transduce1,withCont)
import System.Process.Streaming.Text (utf8x,foldedLines)
program :: CreateProcess
program = piped $ shell " echo aaa ; echo bbbb ; "
firstLine :: IO (Maybe Text)
firstLine = execute program streams
where
streams = foldOut
. transduce1 utf8x
. transduce1 foldedLines
$ withCont Pipes.Prelude.head
该库的依赖足迹比 process 要大得多。
【讨论】:
【参考方案2】:使用的替代方法取决于外部命令的行为。
如果你只是想打断它,你可以hClose outh
。这将关闭管道,并且通过外部命令进一步写入管道将失败并出现“管道损坏”错误。大多数进程在收到此消息后终止。
如果您想读取并丢弃输出,也可以这样做。也许最简单的方法是
do c <- hGetContents outh
evaluate (length c) -- force this to fetch all data
doStuff -- now we are sure that the remote end closed its output
应该在恒定空间中运行。
如果您不想在执行doStuff
之前等待进程结束,请将所有内容包装在forkIO
中。
【讨论】:
doStuff
在生成的进程产生某些内容之前尝试从outh
读取,这是否也会导致“文件结束”错误?
@DamianNadales doStuff
绝不能从outh
读取——上面代码的重点是从outh
读取所有内容并将其丢弃。
这就是问题所在,我只需要读取一行,然后丢弃其余的 :) 否则我可以将其重定向到文件。
@DamianNadales 那么问题是什么?先用getLine
读一行,然后用上面的代码丢弃其余的。
问题是,如果我在进程写入内容之前尝试读取,父进程不会阻塞但会收到文件结束错误。以上是关于读取使用 createProcess 获得的管道的几行,然后将其关闭的主要内容,如果未能解决你的问题,请参考以下文章
无法从通过管道 C++ 重定向的程序中获得正确的输出(Windows)