2012-12-24 22 views
9

Bir haskell programından bir işlem çağırmak ve stdora yanı sıra stderr yakalamak istiyorum.Haskell: System.Process birleştirme stdout ve stderr

yapmam gerekenler:

(_, stdout, stderr) <- readProcessWithExitCode "command" [] "" 

sorun: Bu şekilde, stdout ve stderr ancak mesajları doğru yerde (görünmesini istediğiniz ayrı ayrı yakalanır aksi takdirde sadece stdout ++ stderr hata iletileri ayırır hangi onların stdout meslektaşları). Ben borusunun tam bir dosyaya çıktı ediyorum eğer ben bunu başarmak pek bilmeyiz

, yani

tmp <- openFile "temp.file" ... 
createProcess (proc "command" []) { stdout = UseHandle tmp, 
            stderr = UseHandle tmp } 

Yani benim şimdiki geçici çözüm bir TempFile için boru çıkışlarına ve geri okudum. Ancak daha doğrudan bir yaklaşım arıyorum.

emin ben sadece la

command 2>&1 

á bir kabuk komutu çağırmak istiyorum için ben UNix oldu ve bu kadar olursa. Ancak, bunu olabildiğince taşınabilir hale getirmek istiyorum.

Bunun için neye ihtiyacım var: Belirli bir programı çağırıp çıktıyı basan küçük bir haskell cgi betiği oluşturdum (sadece oynatmak için). Ben çıkıştan html-kaçmak istiyorum, bu yüzden basitçe stdout'a pipetleyemiyorum.

Düşünüyordum: Belki Java'da PipedInputStream/PipedOutputStream veya bellek içinde IO akışlarının işlenmesine izin veren ArrayInputStream/ArrayOutputStream gibi bir bellek içi tanıtıcı oluşturmak mümkündür. Hoogle'da :: Handle numaralı bir işlev için etrafa baktım, ancak bir şey bulamadım.

Belki de iki akışı birleştirmeme izin veren başka bir Haskell modülü var mı?

+0

[ 'createPipe'] (http://hackage.haskell.org/packages/archive/unix/latest/doc/html/System-Posix-IO-ByteString.html#v:createPipe) ve [' fdToHandle (http://hackage.haskell.org/packages/archive/unix/latest/doc/html/System-Posix-IO-ByteString.html#v:fDToHandle) yardımcı olacaktır. –

cevap

6

İki giriş akışını eşzamanlı olarak birleştirmek için pipes'u kullanabilirsiniz.

import Control.Applicative 
import Control.Proxy 
import Control.Concurrent 
import Control.Concurrent.STM 
import System.Process 

toTMVarC :: (Proxy p) => TMVar a ->() -> Consumer p a IO r 
toTMVarC tmvar() = runIdentityP $ forever $ do 
    a <- request() 
    lift $ atomically $ putTMVar tmvar a 

fromTMVarS :: (Proxy p) => TMVar a ->() -> Producer p a IO r 
fromTMVarS tmvar() = runIdentityP $ forever $ do 
    a <- lift $ atomically $ takeTMVar tmvar 
    respond a 

Yakında bir pipes-stm pakette yukarıdaki temel öğeler sağlayacaktır ama şimdilik yukarıdaki kullanın: İlk hüner Eğer stm paketini kullanarak yapabilirsiniz, hangi eş zamanlı iki derelerden okumaktır.

Sonra sadece ayrı MVar her Handle beslemek ve hem eşzamanlı okunan:

main = do 
    (_, mStdout, mStderr, _) <- createProcess (proc "ls" []) 
    case (,) <$> mStdout <*> mStderr of 
     Nothing    -> return() 
     Just (stdout, stderr) -> do 
      out <- newEmptyTMVarIO 
      err <- newEmptyTMVarIO 
      forkIO $ runProxy $ hGetLineS stdout >-> toTMVarC out 
      forkIO $ runProxy $ hGetLineS stderr >-> toTMVarC err 
      let combine() = runIdentityP $ forever $ do 
        str <- lift $ atomically $ 
         takeTMVar out `orElse` takeTMVar err 
        respond str 
      runProxy $ combine >-> putStrLnD 

Sadece giriş işlemek istiyorum ancak birlikte putStrLnD dışarı değiştirin.

pipes package hakkında daha fazla bilgi için, sadece Control.Proxy.Tutorial'u okuyun. (Gerçi bu kolları ve fds kapatmak için nereye emin değilim ..)

3

POSIX sistemi için yeni kulpları bir çift oluşturmak için System.Posix.IO yılında createPipe ve fdToHandle kullanabilirsiniz:

pencereler için
readProcessWithMergedOutput :: String -> IO (ExitCode, String) 
    readProcessWithMergedOutput command = do 
    (p_r, p_w) <- createPipe 
    h_r <- fdToHandle p_r 
    h_w <- fdToHandle p_w 
    (_, _, _, h_proc) <- createProcess (proc command []) 
             { std_out = UseHandle h_w 
             , std_err = UseHandle h_w 
             } 
    ret_code <- waitForProcess h_proc 
    content <- hGetContents h_r 
    return (ret_code, content) 

, this post, bir çapraz platform createPipe uygulamıştır.Belki de