Игнорирование stderr процесса - PullRequest
3 голосов
/ 11 июля 2019

Это должен быть простой вопрос, но пока я не нашел прямого ответа на него: как игнорировать stderr (или stdout) процесса на Haskell, используя processбиблиотека ?Например, допустим, у меня есть следующее:

let proc = (shell "dir /z") {
      std_in  = UseHandle stdin
    , std_out = CreatePipe
    }
(_, out, _, rProc) <- createProcess Proc
exitCode <- waitForProcess rProc

(Примечание: в Windows я знаю, что у dir нет переключателя /z. Вот почему я выбрал его - такЯ мог бы получить интересный вывод о stderr.)

В результате этого только stderr будет выведено на консоль.Теперь допустим, я хочу игнорировать stderr.Как мне это сделать?

Единственный ключ, который я нашел, находится в этой части документации process:

NoStream Закройте дескриптор файла потока, не передавая дескриптор.В системах POSIX это может привести к странному поведению в дочернем процессе, поскольку попытка чтения или записи после закрытия файла приводит к ошибке.Это должно использоваться только с дочерними процессами, которые вообще не используют файловый дескриптор.Если вы хотите игнорировать вывод дочернего процесса, вы должны либо создать канал и слить его вручную, либо передать Handle, который записывает в /dev/null.

Это несколько полезно, но все же оставляет некоторыевопросы без ответа.Можно ли использовать NoStream в системах без POSIX?Это относится к созданию канала и его дренированию, но я не могу найти информацию о том, как это сделать?И /dev/null - это NUL в Windows, за исключением случаев, когда вы используете MSYS или Cygwin, когда он снова /dev/null (я думаю) - поэтому я хочу избежать этого.

Итак, чтобы повторить мой вопрос: какой рекомендуемый, независимый от ОС способ игнорировать stderr процесса?

Ответы [ 2 ]

2 голосов
/ 11 июля 2019

Полагаю, nullStream в наборе типизированного процесса - это то, что вы ищете.

0 голосов
/ 11 июля 2019

Вот один правильный путь:

import Control.Concurrent
import Control.Exception
import System.IO
import System.Process

forceGetContents :: String -> IO ()
forceGetContents s = evaluate (length s) >> return ()

main = do
    outMVar <- newEmptyMVar
    let proc = (shell "dir /z") {
          std_in  = UseHandle stdin
        , std_out = CreatePipe
        , std_err = CreatePipe
        }
    (_, Just out, Just err, rProc) <- createProcess proc
    forkIO (hGetContents err >>= forceGetContents)
    forkIO $ do
        s <- hGetContents out
        forceGetContents s
        putMVar outMVar s
    exitCode <- waitForProcess rProc
    outContents <- takeMVar outMVar
    putStr outContents -- or whatever

Некоторые замечания, которые стоит отметить в комментариях к удаленному ответу:

  1. Вы должны разветвить поток, чтобы очистить канал ошибок.В противном случае, если имеется много ошибок, процесс, который вы запустили, может быть прерван, прежде чем он сможет распечатать их все, что приведет к сбивающему с толку сеансу отладки.
  2. Если , то вы собираетесь waitForProcess,Вы должны раскрутить нить, чтобы слить выходную трубу.В противном случае он может быть уничтожен до того, как сможет распечатать все, что ему нужно, что приведет к неполному выводу.
  3. Это сохранит весь вывод процесса (но не все содержимое потока ошибок) в памяти.Это может быть довольно дорого.
  4. forceGetContents - хороший способ заставить String, возвращаемый hGetContents, быть полностью оцененным, но есть другие String -производители, которые могут нуждаться в болеезадействованная форсирующая функция.См. Также rnf из пакета deepseq.

Вы можете обратиться как к (2), так и к (3), если есть протокол, который, как вы знаете, будет следовать процессу, где вы будете знать, когда он будетсделано, производя продукцию.Затем вы можете передавать поток данных (уменьшая нагрузку на память для битов, которые могут быть отброшены раньше), и можете задерживать waitForProcess до тех пор, пока вы не узнаете, что он завершил вывод (избегая необходимости раскручивать поток, чтобы истощить вывод - хотя по-прежнему требуетсяраздвоенная ветка за ошибки!).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...