我如何在 Idris 中调用子流程?
How can I call a subprocess in Idris?
Idris 标准库(或第三方库)中是否有一些模块允许 shell 输出到另一个程序?我正在考虑像 Python 的 subprocess
和 Haskell 的 System.Process
这样的模块。
理想情况下,我想以编程方式与进程交互(写入其标准输入、读取其标准输出等)。
有一个 system : String -> IO Int
函数,它接受一个 shell 命令,运行 是它,return 是它的退出代码。您需要 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
在第二种情况下,我希望它是 return 1
而不是 256
。至少 echo $?
显示的是这样。
可以基于Effects
库制作另一个版本,在this教程中有描述:
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 标准库中已经有绑定。
例如,让我展示一下我们如何从子进程的标准输出中读取数据(请记住,这是一个带有基本错误处理的简单片段):
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
Idris 标准库(或第三方库)中是否有一些模块允许 shell 输出到另一个程序?我正在考虑像 Python 的 subprocess
和 Haskell 的 System.Process
这样的模块。
理想情况下,我想以编程方式与进程交互(写入其标准输入、读取其标准输出等)。
有一个 system : String -> IO Int
函数,它接受一个 shell 命令,运行 是它,return 是它的退出代码。您需要 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
在第二种情况下,我希望它是 return 1
而不是 256
。至少 echo $?
显示的是这样。
可以基于Effects
库制作另一个版本,在this教程中有描述:
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 标准库中已经有绑定。
例如,让我展示一下我们如何从子进程的标准输出中读取数据(请记住,这是一个带有基本错误处理的简单片段):
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