What is process-extras

You might want to use this package if

  • You want to read and write ByteStrings or Text to a process rather than just Strings
  • You want to read output from a non-terminating process (e.g. yes(1))
  • You want more flexibility in process creation
  • You want various types of progress output from the process to the console before capturing its output - indented and prefixed output, reporting of the command that started the process, dots to reflect the size of the process output, etc.


This project is available on GitHub. You may contribute changes there.

Please report bugs and feature requests using the GitHub issue tracker.


The output type of the raw system process functions is ByteString. Instances of ListLikeProcessIO are provided to read as type String, Text, Lazy Text, ByteString, or Lazy ByteString. Select by casting the result, or by specifying the module containing the specialized function:

> :m +System.Process.ListLike Data.ByteString Data.Text.Lazy
> readCreateProcess (shell "echo 'λ'") mempty :: IO (ExitCode, ByteString, ByteString)
> readCreateProcess (shell "echo 'λ'") mempty :: IO (ExitCode, Text, Text)
> readCreateProcess (shell "echo 'λ'") mempty :: IO (ExitCode, String, String)
> readCreateProcess (shell "yes | head -10") mempty :: IO (ExitCode, Text, Text)

Although the output type can be lazy, normal process functions still need to read until EOF on the process output before returing anything. If you have a process whose output never ends you can use the readCreateProcessLazy function to read it. Functions like readProcess would block waiting for EOF on the process output:

> (Prelude.take 4 <$> readCreateProcessLazy (proc "yes" []) mempty :: IO [Chunk Text]) >>= mapM_ (putStrLn . show)
ProcessHandle <process>
Stdout "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny ..."

The output type can be any instance of ProcessOutput, instances for types (ExitCode, a, a), [Chunk a], and (ExitCode, [Chunk a]) are provided. [Chunk a] can be converted to any other instance of ProcessOutput using collectOutput

> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk ByteString]) >>= mapM_ (Prelude.putStrLn . show)
Stdout "\US\139\b\NUL\237\136\&7W\NUL\ETX345\183\&403\215\&31Q04267\177\&0\177\212\&33\225\STX\NUL_\169\142\178\ETB\NUL\NUL\NUL"
Stderr "gzip: stdin: file size changed while zipping\n -8.7%\n"
Result ExitSuccess
> (readCreateProcess (shell "uptime") mempty :: IO [Chunk ByteString]) >>= writeOutput
 14:00:34 up 18 days,  7:16,  6 users,  load average: 0.04, 0.10, 0.08
> collectOutput <$> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk ByteString]) :: IO (ExitCode, ByteString, ByteString)
(ExitSuccess,"\US\139\b\NUL\185\137\&7W\NUL\ETX345\183\&427\212\&33W0426731\177\208\&35\225\STX\NUL\237\192\CAN\224\ETB\NUL\NUL\NUL","gzip: stdin: file size changed while zipping\n -8.7%\n")
> collectOutput <$> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk ByteString]) :: IO (ExitCode, ByteString, ByteString)
(ExitSuccess,"\US\139\b\NUL\185\137\&7W\NUL\ETX345\183\&427\212\&33W0426731\177\208\&35\225\STX\NUL\237\192\CAN\224\ETB\NUL\NUL\NUL","gzip: stdin: file size changed while zipping\n -8.7%\n")
> (collectOutput . Prelude.filter (\x -> case x of Stderr _ -> False; _ -> True)) <$> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk ByteString]) :: IO (ExitCode, ByteString, ByteString)

Some cases that need investigation:

> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk String]) >>= mapM_ (putStrLn . show)
*** Exception: fd:13: hGetContents: invalid argument (invalid byte sequence)
> (readCreateProcess (shell "gzip -v < /proc/uptime") mempty :: IO [Chunk Text]) >>= mapM_ (putStrLn . show)
*** Exception: fd:13: hClose: invalid argument (Bad file descriptor)


haskell-process-extras (0.7.1) unstable; urgency=low

* Add System.Process.Run, utilities and a monad for process progress
* Rename ProcessOutput -> ProcessResult
* Add a ProcessText class to characterize the type written to
standard input and read from standard output and error.
* Add an alias for readCreateProcess named readCreateProcessStrict
* Update README.md

-- David Fox <dsf@foxthompson.net> Mon, 05 Dec 2016 10:52:20 -0800

haskell-process-extras (0.5) unstable; urgency=low

* Have writeOutput return the input list rather than ()
* Additional re-exports from the process package

-- David Fox <dsf@foxthompson.net> Mon, 21 Nov 2016 12:45:57 -0800

haskell-process-extras ( unstable; urgency=low

* Add changelog and .ghci to Extra-Source-Files list.

-- David Fox <dsf@seereason.com> Sun, 15 May 2016 09:20:54 -0700

haskell-process-extras ( unstable; urgency=low

* Actually check changelog into git.

-- David Fox <dsf@seereason.com> Sun, 15 May 2016 09:00:03 -0700

haskell-process-extras (0.4) trusty-seereason; urgency=low

* Add changelog
* Wrap all the input processing with a catch resource vanished
* Add foldOutput and writeOutput, for handling Chunk streams.
* Add some examples in README.md.

-- David Fox <dsf@seereason.com> Sun, 15 May 2016 08:59:47 -0700
comments powered byDisqus