Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Haskell中执行一系列shell命令并在出现错误时中断?_Shell_Haskell_Monads - Fatal编程技术网

如何在Haskell中执行一系列shell命令并在出现错误时中断?

如何在Haskell中执行一系列shell命令并在出现错误时中断?,shell,haskell,monads,Shell,Haskell,Monads,假设我有一个表示要执行的shell命令的Strings列表 commands = ["git clone https://github.com/test/repo.git", "git checkout origin"] 另外,假设我有一个命令,execCommand,它接受一个字符串,作为shell命令执行,检索退出代码stdout和stderr,如果退出代码为非零,则返回stdout和stderr的串联;否则,它将返回Nothing 现在,我如何顺序执行命令列表,同时确保后续命令不会在一个

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

commands = ["git clone https://github.com/test/repo.git", "git checkout origin"]
另外,假设我有一个命令,
execCommand
,它接受一个字符串,作为shell命令执行,检索退出代码stdout和stderr,如果退出代码为非零,则返回stdout和stderr的串联;否则,它将返回
Nothing

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

下面是
execCommand
的完整代码

import System.IO
import System.Process
import System.Exit

createCommand :: String -> FilePath -> CreateProcess
createCommand command curDir =
  (shell command){std_out = CreatePipe, std_err = CreatePipe, cwd = Just curDir}

execCommand :: String -> FilePath -> IO (Maybe String)
execCommand command curDir = do
  (_, Just hout, Just herr, procHandle) <- createProcess $ createCommand command curDir
  exitCode <- waitForProcess procHandle
  stdOut   <- hGetContents hout
  stdErr   <- hGetContents herr
  if exitCode /= ExitSuccess
     then return $ Just $ concat [stdOut, stdErr]
     else return $ Nothing
import System.IO
导入系统。进程
导入系统。退出
createCommand::String->FilePath->CreateProcess
createCommand命令curDir=
(shell命令){std_out=CreatePipe,std_err=CreatePipe,cwd=Just curDir}
execCommand::字符串->文件路径->IO(可能是字符串)
execCommand curDir=do

(u,Just hout,Just herr,procHandle)您可以使用
mapM_u
,它的类型为

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

以及适当的短路行为。

这可能会解决您的问题:

{-# 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
{-#语言灵活实例}
导入系统.IO
导入系统。进程
导入系统。退出
导入控制。异常
进口管制
导入控制.Monad.IO.Class
进口管制。单子。翻译。也许
createCommand::CmdSpec->FilePath->CreateProcess
createCommand(ShellCommand命令)curDir=
(shell命令){std_out=CreatePipe,std_err=CreatePipe,cwd=Just curDir}
createCommand(RawCommand命令参数)curDir=
(proc命令参数){std_out=CreatePipe,std_err=CreatePipe,cwd=Just curDir}
execCommand::CmdSpec->FilePath->IO()
execCommand curDir=do

(uu,Just hout,Just herr,prochhandle)好吧,我很确定我找到了答案。我不再使用“花哨”的东西,而是转而使用好的ol'递归

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
runCommands::[String]->FilePath->IO(可能是String)
runCommands[]\=不返回任何内容
runCommands(命令:rest)curDir=do
结果run命令rest curDir
Just err->return$Just err

我的第一个问题是为什么在这里使用
字符串Bool
。这很奇怪,有两个原因。1.按照惯例,由于其
函子
应用程序
、以及
单子
实例的编写方式,
右侧
是“一切顺利”的一侧,
左侧
是“有什么事情发生了意外”的一侧。2.如果奇怪的一面总是
真的
,你为什么需要它?一种选择是使用
可能是String
。然而,更自然的方法是使用
或Int-String
,这样您要么得到串联输出,要么得到退出代码。(CONT)(CONT)另一个需要考虑的自然事物(也许不是在您的应用程序中)是<代码>(INT,String)字符串
,它给出标准输出或给出标准错误和退出代码。(编辑:我实际上不确定退出代码是什么类型。它很可能不是
Int
)嗯,还有一些带有类型签名的东西。您试图使用monad transformer而没有实际使用它,这可能会在将来给您带来很多痛苦。你应该在标准库中查找Edward Kmett或ErrorT制作的软件包。@Julián,在
transformers
@dfeuer中也有
Control.Monad.Trans.other
,因为我刚刚查找了它,而它来自于任何一个软件包。尽管再次查看代码会提醒我,标准库中使用IO时存在抛出和捕获。因此,当某些东西失败时抛出异常可能更好。