Idris标准库(或第三方库)中是否有一些模块可以允许用户使用Shell扩展到另一个程序?我正在考虑像Python的subprocess和Haskell的System.Process这样的模块。

理想情况下,我想以编程方式与该流程进行交互(写入其stdin,从其stdout读取等)。

最佳答案

有一个system : String -> IO Int函数,它接受一个shell命令,运行它,并返回其退出代码。您需要import System才能使用它:

import System

main : IO ()
main = do
  exitCode <- system "echo HelloWorld!"
  putStrLn $ "Exit code: " ++ show exitCode

  exitCode <- system "echo HelloWorld!; false"
  putStrLn $ "Exit code: " ++ show exitCode

在我的系统上,以上代码导致以下输出:
HelloWorld!
Exit code: 0
HelloWorld!
Exit code: 256

我希望它在第二种情况下返回1而不是256。至少这是echo $?显示的内容。

可以在this教程中介绍的Effects库的基础上制作另一个版本:
import Effects
import Effect.System
import Effect.StdIO

execAndPrint : (cmd : String) -> Eff () [STDIO, SYSTEM]
execAndPrint cmd = do
  exitCode <- system cmd
  putStrLn $ "Exit code: " ++ show exitCode

script : Eff () [STDIO, SYSTEM]
script = do
  execAndPrint "echo HelloWorld!"
  execAndPrint "sh -c \"echo HelloWorld!; exit 1\""

main : IO ()
main = run script

在这里,我们需要向Idris解释它需要Effects包:
idris -p effects <filename.idr>

我不知道有任何Idris库可让您轻松使用子进程的stdin/stdout。作为一种解决方法,我们可以利用C的管道工具,即popen/pclose函数,该区域在Idris标准库中具有绑定(bind)。
让我展示一下如何从子流程的stdout中读取内容(请记住,这是一个简单的代码段,具有基本的错误处理功能):
import System

-- read the contents of a file
readFileH : (fileHandle : File) -> IO String
readFileH h = loop ""
  where
    loop acc = do
      if !(fEOF h) then pure acc
      else do
        Right l <- fGetLine h | Left err => pure acc
        loop (acc ++ l)

execAndReadOutput : (cmd : String) -> IO String
execAndReadOutput cmd = do
  Right fh <- popen cmd Read | Left err => pure ""
  contents <- readFileH fh
  pclose fh
  pure contents

main : IO ()
main = do
  out <- (execAndReadOutput "echo \"Captured output\"")
  putStrLn "Here is what we got:"
  putStr out

运行程序时,您应该看到
Here is what we got:
Captured output

关于process - 如何在Idris中调用子流程?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39812465/

10-12 17:40