假设我有一个代表要执行的shell命令的String
列表。
commands = ["git clone https://github.com/test/repo.git", "git checkout origin"]
另外,假设我有一个命令,execCommand
接受一个字符串,将其作为shell命令执行,检索退出代码,stdout和stderr,如果退出代码非零,则返回{{1 stdout和stderr的串联;否则,它返回Just
。
现在,我如何顺序执行命令列表,同时确保在一个命令产生错误后后续命令不执行?
以下是Nothing
的完整代码。
execCommand
答案 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 ()
和适当的短路行为。