haskell: cd 命令在 shake/command 库中不起作用

haskell: cd command does not work in shake/command library

出于某种原因,我无法使 cd 命令在 shake/command Haskell 库中工作。它认为我用 cd 调用的目录不存在,即使它存在于文件系统中。

这是我的代码的摘录:

dataDir = "data"

data Settings = Settings {
  url :: String
} deriving (Eq, Show, Generic, JSON.ToJSON, JSON.FromJSON)

settings :: String -> Handler Settings
settings subfolder = let 
  gitPath = dataDir ++ "/" ++ subfolder ++ "/git/.git"
  in do
    pathExists <- liftIO $ doesPathExist gitPath 
    -- Stdout pwdOut <- liftIO $ cmd ("pwd" :: String)
    -- liftIO $ putStrLn $ pwdOut 
    if not pathExists
       then do
         liftIO $ (cmd_ ("mkdir -p" :: String) [gitPath] :: IO ())
         liftIO $ (cmd_ ("cd" :: String) [gitPath] :: IO ())
         liftIO $ (cmd_ ("git init" :: String) :: IO ())
         return $ Settings { url = ""}
       else do
         liftIO $ (cmd_ (Cwd ".") ("cd" :: String) [gitPath] :: IO ())
         Stdout out <- liftIO $ (cmd ("git config --get remote.origin.url" :: String))
         return $ Settings {url = out} 

在两种情况下都失败并出现错误 cd: createProcess: runInteractiveProcess: exec: does not exist (No such file or directory):如果目录存在并且当执行 mkdir 命令时。

无法理解它。但在我向 shake 的 github 页面提交错误之前,我想与您确认我没有做任何可能导致这种行为的愚蠢行为。

在此先感谢您的帮助。

Shake 的 Haddock page describes cmd_, and links to its source. There we can see that cmd_ eventually calls commandExplicitIO, which constructs a ProcessOpts with RawCommand and passes it to process. process then takes that ProcessOpts, pattern-matches it as a RawCommand (via cmdSpec), and calls proc. We have now entered the well-documented zone:您必须给 proc 一个 可执行文件 ,而 cd 不是可执行文件。 (为什么?由于进程无法更改其父进程的工作目录,因此 cd 必须是 shell 内置。)

如其他答案所述,cd 不是可执行文件,因此如果您想 运行 它,则必须将 Shell 传递给 cmd .

但是,几乎可以肯定的是,您不想在命令中调用 cd,因为它 不会 更改任何后续目录命令。每个 cmd 都是一个单独的进程,具有单独的环境,因此后续命令将在一个全新的环境中,并且与 cd 之前的工作目录相同。解决方案是将 (Cwd gitPath) 传递给每个要对给定目录进行操作的命令。