Is there some module in the Idris standard library (or a third party library) that allows one to shell out to another program? I'm thinking of modules like Python's subprocess
and Haskell's System.Process
.
Ideally, I'd like to interact programmatically with the process (writing to its stdin, reading from its stdout, etc.).
There is the system : String -> IO Int
function which takes a shell command, runs it, and returns its exit code. You'll need to import System
to use it:
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
On my system the above code results in the following output:
HelloWorld!
Exit code: 0
HelloWorld!
Exit code: 256
I'd expect it to return 1
instead of 256
in the second case. At least it's what echo $?
shows.
Another version can be made basing on the Effects
library, which is described in this tutorial:
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
Here we need to explain to Idris that it needs the Effects
package:
idris -p effects <filename.idr>
I'm not aware of any Idris library that lets you easily work with stdin/stdout of a subprocess. As a workaround we can use the pipes facilities of C, utilizing its popen
/ pclose
functions, which aready have bindings in the Idris standard library.
Let me show how we could, for example, read from stdout of a subprocess (please bear in mind that it's a simple snippet with rudimentary error processing):
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
When you run the program, you should see
Here is what we got:
Captured output
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With