Using external programs with Haskell in windows.

I'm looking for a way to run an external program and get the results in haskell. Something similar to HSH but that will work in windows. I don't need anything too complex, just to provide the command to be run as a string and get the result as a string. Is this possible? One of the HSH examples is all I need: runS $ "echo /etc/pass*" -> "/etc/passwd /etc/passwd-"

christian.lean2:
I'm looking for a way to run an external program and get the results in haskell. Something similar to HSH but that will work in windows. I don't need anything too complex, just to provide the command to be run as a string and get the result as a string. Is this possible? One of the HSH examples is all I need:
runS $ "echo /etc/pass*" -> "/etc/passwd /etc/passwd-"
System.Process is your friend. E.g. import System.Process import Control.Exception import System.IO import System.Exit -- -- Run a normal shell command -- run :: String -> IO String run s = handle (fail . show) $ do (ih,oh,eh,pid) <- runInteractiveCommand s so <- hGetContents oh se <- hGetContents eh hClose ih ex <- waitForProcess pid case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so *Process> run $ "echo *.hs" "Main.hs Process.hs Shell.hs\n" -- Don

Donald Bruce Stewart wrote:
christian.lean2:
I'm looking for a way to run an external program and get the results in haskell. Something similar to HSH but that will work in windows. I don't need anything too complex, just to provide the command to be run as a string and get the result as a string. Is this possible? One of the HSH examples is all I need:
runS $ "echo /etc/pass*" -> "/etc/passwd /etc/passwd-"
System.Process is your friend. E.g.
import System.Process import Control.Exception import System.IO import System.Exit
-- -- Run a normal shell command -- run :: String -> IO String run s = handle (fail . show) $ do (ih,oh,eh,pid) <- runInteractiveCommand s so <- hGetContents oh se <- hGetContents eh hClose ih ex <- waitForProcess pid case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so
*Process> run $ "echo *.hs" "Main.hs Process.hs Shell.hs\n"
-- Don
Thank you for the speedy reply, I am trying to follow what the code is trying to do, is this correct? runInteractiveCommand: This gives you handles for stdin, stdout, stderr, and the process running the command. You can then use functions like hPutStrLn with stdin or hGetContents with stdout and stderr. waitForProcess just stops that part of the code until the command has finished. Is nClose ih necessary, none of the others are closed so I'm guessing this is needed else waitForProcess will never finish. Does this have to do with run_Interactive_Command, could I keep passing commands and getting responses until I close the input. The two parts i'm having trouble following are: run s = handle (fail . show) $ do handle has type: handle :: (Exception -> IO a) -> IO a -> IO a Is (fail . show) composing a fuction of type Exception -> IO a) and what part is the middle IO a, is that the whole block that follows(ie the do block) Also case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so I dont quite get this part. I understand that you are checking for errors(not (null se)) otherwise returning everything gotten from stdout but I don't get the ExitFailure line. I have one final question, how should you go about finding functions like runInteractiveCommand? If I had that to begin with I might have had a chance to try some of the above on my own but I find that it is difficult to know where to start.

christian.lean2:
Donald Bruce Stewart wrote:
christian.lean2:
I'm looking for a way to run an external program and get the results in haskell. Something similar to HSH but that will work in windows. I don't need anything too complex, just to provide the command to be run as a string and get the result as a string. Is this possible? One of the HSH examples is all I need:
runS $ "echo /etc/pass*" -> "/etc/passwd /etc/passwd-"
System.Process is your friend. E.g.
import System.Process import Control.Exception import System.IO import System.Exit
-- -- Run a normal shell command -- run :: String -> IO String run s = handle (fail . show) $ do (ih,oh,eh,pid) <- runInteractiveCommand s so <- hGetContents oh se <- hGetContents eh hClose ih ex <- waitForProcess pid case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so
*Process> run $ "echo *.hs" "Main.hs Process.hs Shell.hs\n"
-- Don
Thank you for the speedy reply, I am trying to follow what the code is trying to do, is this correct? runInteractiveCommand: This gives you handles for stdin, stdout, stderr, and the process running the command. You can then use functions like hPutStrLn with stdin or hGetContents with stdout and stderr.
Right.
waitForProcess just stops that part of the code until the command has finished.
Yep.
Is nClose ih necessary, none of the others are closed so I'm guessing this is needed else waitForProcess will never finish.
They should be closed too I suspect.
Does this have to do with run_Interactive_Command, could I keep passing commands and getting responses until I close the input.
Not with that code, but you could modify it to do so.
The two parts i'm having trouble following are:
run s = handle (fail . show) $ do
That's an exception handler that just shows the exception in the current monad.
handle has type:
handle :: (Exception -> IO a) -> IO a -> IO a
Is (fail . show) composing a fuction of type
Exception -> IO a)
and what part is the middle IO a, is that the whole block that follows(ie the do block)
Yes.
Also
case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so
I dont quite get this part. I understand that you are checking for errors(not (null se)) otherwise returning everything gotten from stdout but I don't get the ExitFailure line.
That checks the exit status of the program, as reported by waitForProcess, the other cases check for stderr.
I have one final question, how should you go about finding functions like runInteractiveCommand?
hoogle! http://www.haskell.org/hoogle/?q=Command
If I had that to begin with I might have had a chance to try some of the above on my own but I find that it is difficult to know where to start.
Hoogle, and the library docs, are helpful here. -- Don

Donald Bruce Stewart wrote:
christian.lean2:
Donald Bruce Stewart wrote:
christian.lean2:
I'm looking for a way to run an external program and get the results in haskell. Something similar to HSH but that will work in windows. I don't need anything too complex, just to provide the command to be run as a string and get the result as a string. Is this possible? One of the HSH examples is all I need:
runS $ "echo /etc/pass*" -> "/etc/passwd /etc/passwd-"
System.Process is your friend. E.g.
import System.Process import Control.Exception import System.IO import System.Exit
-- -- Run a normal shell command -- run :: String -> IO String run s = handle (fail . show) $ do (ih,oh,eh,pid) <- runInteractiveCommand s so <- hGetContents oh se <- hGetContents eh hClose ih ex <- waitForProcess pid case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so
*Process> run $ "echo *.hs" "Main.hs Process.hs Shell.hs\n"
-- Don
Thank you for the speedy reply, I am trying to follow what the code is trying to do, is this correct? runInteractiveCommand: This gives you handles for stdin, stdout, stderr, and the process running the command. You can then use functions like hPutStrLn with stdin or hGetContents with stdout and stderr.
Right.
waitForProcess just stops that part of the code until the command has finished.
Yep.
Is nClose ih necessary, none of the others are closed so I'm guessing this is needed else waitForProcess will never finish.
They should be closed too I suspect.
Does this have to do with run_Interactive_Command, could I keep passing commands and getting responses until I close the input.
Not with that code, but you could modify it to do so.
The two parts i'm having trouble following are:
run s = handle (fail . show) $ do
That's an exception handler that just shows the exception in the current monad.
handle has type:
handle :: (Exception -> IO a) -> IO a -> IO a
Is (fail . show) composing a fuction of type
Exception -> IO a)
and what part is the middle IO a, is that the whole block that follows(ie the do block)
Yes.
Also
case ex of ExitFailure e -> fail $ "Failed with status: " ++ show e _ | not (null se) -> fail se | otherwise -> return so
I dont quite get this part. I understand that you are checking for errors(not (null se)) otherwise returning everything gotten from stdout but I don't get the ExitFailure line.
That checks the exit status of the program, as reported by waitForProcess, the other cases check for stderr.
I have one final question, how should you go about finding functions like runInteractiveCommand?
hoogle!
http://www.haskell.org/hoogle/?q=Command
If I had that to begin with I might have had a chance to try some of the above on my own but I find that it is difficult to know where to start.
Hoogle, and the library docs, are helpful here.
-- Don
Just a quick thankyou, the response has been very helpful.
participants (2)
-
Christian Lean
-
dons@cse.unsw.edu.au