如何在Windows上正确捕获和打印stderr和/或stdout?

时间:2011-09-28 19:29:48

标签: haskell

感谢hammar,我开始在Windows上运行作业管理服务器。目的是unix-side守护进程将向windows端发送命令并从windows端接收stderr / stdout。问题是,我无法让Windows端服务器在Windows端打印到stderr / stdout,也不能将流发送到连接到unix端的句柄(现在使用telnet客户端)。

这是我的尝试。我在这个例子中只使用了stdout,但stdout和stderr都不起作用。 runJob是我正在尝试的IO动作。我希望能解决这个问题。

编辑:我运行了一个haskell测试脚本来代替.bat文件,它捕获了stdout / stderr。下面我包括批处理文件。令我困惑的是,当我手动运行批处理文件时,它会生成stdout和stderr到屏幕。无法弄清楚发生了什么。也许我应该用haskell脚本替换批处理文件。

> import Network.Socket
> import Control.Monad
> import Network
> import System.Environment (getArgs)
> import System.Process
> import System.IO
> import Control.Concurrent (forkIO)
> import Control.Exception (bracket)
> import Data.Maybe

> main :: IO ()
> main = withSocketsDo $ do
>    putStrLn ("up top\n")
>    [port] <- getArgs
>    bracket (prepareSocket (fromIntegral $ read port))
>            sClose
>            acceptConnections

> prepareSocket :: PortNumber -> IO Socket
> prepareSocket port = do
>    sock <- socket AF_INET Stream defaultProtocol 
>    let socketAddress = SockAddrInet port 0000 
>    bindSocket sock socketAddress
>    listen sock 1
>    putStrLn $ "Listening on " ++ (show port)
>    return sock

> acceptConnections :: Socket -> IO ()
> acceptConnections sock' = do
>    forever $ do
>        (sock, sockAddr) <- Network.Socket.accept sock'
>        handle <- socketToHandle sock ReadWriteMode
>        sockHandler sock handle

> sockHandler :: Socket -> Handle -> IO ()
> sockHandler sock' handle = do
>     hSetBuffering handle LineBuffering
>     -- Add the forkIO back if you want to allow concurrent connections.
>     {- forkIO  $ -}
>     commandProcessor handle
>     return ()

> commandProcessor :: Handle -> IO ()
> commandProcessor handle = untilM (hIsEOF handle) handleCommand >> hClose handle
>   where
>     handleCommand = do
>         line <- hGetLine handle
>         let (cmd:arg) = words line
>         case cmd of
>             "echo" -> echoCommand handle arg 
>             "runjob" -> runJob handle arg
>             _ -> do hPutStrLn handle "Unknown command"

> echoCommand :: Handle -> [String] -> IO ()
> echoCommand handle arg = do
>     hPutStrLn handle (unwords arg)

> runJob :: Handle -> [String] -> IO ()
> runJob handle jobNumber = do
>        
>   --  let batchDirectory = "fookit" 
>     (_, Just hout, Just herr, jHandle) <-  
>         createProcess (proc testJob [])  { cwd = Just batchDirectory, 
>                                                    std_out = CreatePipe, 
>                                                    std_err = CreatePipe }
>     stdOUT <- hGetLine herr
>     hPutStrLn stdout stdOUT
>     hPutStrLn handle stdOUT 
>     exitCode <- waitForProcess jHandle 
>    -- stdErr <- hShow hout                                           
>     --hPutStrLn handle stdOUT 
>     return ()

> batchDirectory = "C:\\Users\\ixia\\Documents"
> testJob = "C:\\Users\\ixia\\Documents\\680batch.bat"
> untilM cond action = do
>    b <- cond
>    if b
>      then return ()
>      else action >> untilM cond action

这是我提到的批处理文件。它执行手动运行时的预期

“C:\ Program Files(x86)\ Ixia \ Tcl \ 8.4.14.0 \ bin \ tclsh.exe”680template.tcl

1 个答案:

答案 0 :(得分:3)

让我们尝试通过消除所有网络代码来缩小范围并使其更容易测试,因为它实际上与捕获进程的输出无关。这是从您的代码中提取的一个小测试程序。

import System.IO
import System.Process

main = do
    (_, Just hout, Just herr, jHandle) <-
        -- Replace with some other command on Windows
        createProcess (proc "/bin/date" [])
           { cwd = Just "."
           , std_out = CreatePipe
           , std_err = CreatePipe 
           }

    putStrLn "First line of stdout:"
    hGetLine hout >>= putStrLn

    exitCode <- waitForProcess jHandle
    putStrLn $ "Exit code: " ++ show exitCode

至少可以在Ubuntu上按预期工作。 (目前我附近没有Windows框。)

$ runghc RunJob.hs
First line of stdout:
Wed Sep 28 22:28:37 CEST 2011
Exit code: ExitSuccess

我首先要测试一下这适用于你的工作。那应该会给你一些如何从那里开始的线索。