如何在Haskell中执行一系列shell命令并打破错误?

时间:2015-01-28 16:41:35

标签: shell haskell monads

假设我有一个代表要执行的shell命令的String列表。

commands = ["git clone https://github.com/test/repo.git", "git checkout origin"]

另外,假设我有一个命令,execCommand接受一个字符串,将其作为shell命令执行,检索退出代码,stdout和stderr,如果退出代码非零,则返回{{1 stdout和stderr的串联;否则,它返回Just

现在,我如何顺序执行命令列表,同时确保在一个命令产生错误后后续命令不执行?

以下是Nothing的完整代码。

execCommand

3 个答案:

答案 0 :(得分:2)

嗯,这可能会解决您的问题:

{-# LANGUAGE FlexibleInstances #-}
import System.IO
import System.Process
import System.Exit
import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe

createCommand :: CmdSpec -> FilePath -> CreateProcess
createCommand (ShellCommand command) curDir =
  (shell command){std_out = CreatePipe, std_err = CreatePipe, cwd = Just curDir}
createCommand (RawCommand command arguments) curDir =
  (proc command arguments){std_out = CreatePipe, std_err = CreatePipe, cwd = Just curDir}

execCommand :: CmdSpec -> FilePath -> IO ()
execCommand command curDir = do
    (_, Just hout, Just herr, procHandle) <- createProcess $ createCommand command curDir
    exitCode <- waitForProcess procHandle
    when (exitCode /= ExitSuccess) $ do
        stdOut   <- hGetContents hout
        stdErr   <- hGetContents herr
        throwIO $ stdOut ++ stdErr

instance Exception String

execList :: [(CmdSpec, FilePath)] -> MaybeT IO String
execList xs = do
    out <- liftIO $ try $ mapM_ (uncurry execCommand) xs
    case out of
        Left c -> return c
        Right _ -> mzero

请注意,这使用FlexibleInstances。这是使String成为Exception类型类的一个实例所必需的(问题在于String = [Char])。您可以通过创建一个包含字符串并使其成为Exception实例的新类型来删除扩展。

答案 1 :(得分:1)

嗯,我很确定我明白了。而不是使用&#34; fancy&#34;东西,我又回到了好的地步。递归。

runCommands :: [String] -> FilePath -> IO (Maybe String)
runCommands [] _ = return Nothing
runCommands (command:rest) curDir = do
  result <- execCommand command curDir
  case result of
    Nothing  -> runCommands rest curDir
    Just err -> return $ Just err

答案 2 :(得分:0)

您可以使用mapM_,其类型为

mapM_ :: ( (CmdSpec, FilePath)  -> ExceptT String IO ())
      ->  [(CmdSpec, FilePath)] -> ExceptT String IO ()

和适当的短路行为。