System.Process

process-1.0.1.5: Process libraries

Portability | non-portable (requires concurrency)
Stability | experimental
Maintainer | libraries@haskell.org

System.Process

Contents

- Running sub-processes
  - Specific variants of createProcess
- Process completion

Description

Operations for creating and interacting with sub-processes.

Synopsis

- createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- shell :: String -> CreateProcess
- proc :: FilePath -> [String] -> CreateProcess
- data CreateProcess = CreateProcess {
  - cmdspec :: CmdSpec
  - cwd :: Maybe FilePath
  - env :: Maybe [(String, String)]
  - std_in :: StdStream
  - std_out :: StdStream
  - std_err :: StdStream
  - close_fds :: Bool
  }
- data CmdSpec
  - = ShellCommand String
  - | RawCommand FilePath [String]
- data StdStream
  - = Inherit
  - | UseHandle Handle
  - | CreatePipe
- data ProcessHandle
- runCommand :: String -> IO ProcessHandle
- runProcess :: FilePath -> [String] -> Maybe FilePath -> Maybe [(String, String)] -> Maybe Handle -> Maybe Handle -> Maybe Handle -> IO ProcessHandle
- runInteractiveCommand :: String -> IO (Handle, Handle, Handle, ProcessHandle)
- runInteractiveProcess :: FilePath -> [String] -> Maybe FilePath -> Maybe [(String, String)] -> IO (Handle, Handle, Handle, ProcessHandle)
- readProcess :: FilePath -> [String] -> String -> IO String
- readProcessWithExitCode :: FilePath -> [String] -> String -> IO (ExitCode, String, String)
- system :: String -> IO ExitCode
- rawSystem :: String -> [String] -> IO ExitCode
- waitForProcess :: ProcessHandle -> IO ExitCode
- getProcessExitCode :: ProcessHandle -> IO (Maybe ExitCode)
- terminateProcess :: ProcessHandle -> IO ()

# Running sub-processes

createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)

This is the most general way to spawn an external process. The process can be a command line to be executed by a shell or a raw command with a list of arguments. The stdin, stdout, and stderr streams of the new process may individually be attached to new pipes, to existing `Handle`s, or just inherited from the parent (the default.)

The details of how to create the process are passed in the `CreateProcess` record. To make it easier to construct a `CreateProcess`, the functions `proc` and `shell` are supplied that fill in the fields with default values which can be overriden as needed.

`createProcess` returns `(mb_stdin_hdl, mb_stdout_hdl, mb_stderr_hdl, p)`, where

- if `std_in == CreatePipe`, then `mb_stdin_hdl` will be `Just h`, where `h` is the write end of the pipe connected to the child process's `stdin`.
- otherwise, `mb_stdin_hdl == Nothing`

Similarly for `mb_stdout_hdl` and `mb_stderr_hdl`.

For example, to execute a simple `ls` command:

       r <- createProcess (proc "ls" [])

To create a pipe from which to read the output of `ls`:

       (_, Just hout, _, _) <-
           createProcess (proc "ls" []){ std_out = CreatePipe }

To also set the directory in which to run `ls`:

       (_, Just hout, _, _) <-
           createProcess (proc "ls" []){ cwd = Just "\home\bob",
                                         std_out = CreatePipe }

shell :: String -> CreateProcess

Construct a `CreateProcess` record for passing to `createProcess`, representing a command to be passed to the shell.

proc :: FilePath -> [String] -> CreateProcess

Construct a `CreateProcess` record for passing to `createProcess`, representing a raw command with arguments.

data CreateProcess

Constructors

CreateProcess |
Fields cmdspec :: CmdSpec Executable & arguments, or shell command cwd :: Maybe FilePath Optional path to the working directory for the new process env :: Maybe [(String, String)] Optional environment (otherwise inherit from the current process) std_in :: StdStream How to determine stdin std_out :: StdStream How to determine stdout std_err :: StdStream How to determine stderr close_fds :: Bool Close all file descriptors except stdin, stdout and stderr in the new process (on Windows, only works if std_in, std_out, and std_err are all Inherit)

data CmdSpec

Constructors

ShellCommand String | a command line to execute using the shell
RawCommand FilePath [String] | the filename of an executable with a list of arguments

data StdStream

Constructors

Inherit | Inherit Handle from parent
UseHandle Handle | Use the supplied Handle
CreatePipe | Create a new pipe. The returned `Handle` will use the default encoding and newline translation mode (just like `Handle`s created by `openFile`).

data ProcessHandle

## Specific variants of createProcess

runCommand :: String -> IO ProcessHandle

Runs a command using the shell.

runProcess

Arguments

:: FilePath | Filename of the executable
-> [String] | Arguments to pass to the executable
-> Maybe FilePath | Optional path to the working directory
-> Maybe [(String, String)] | Optional environment (otherwise inherit)
-> Maybe Handle | Handle to use for `stdin` (Nothing => use existing `stdin`)
-> Maybe Handle | Handle to use for `stdout` (Nothing => use existing `stdout`)
-> Maybe Handle | Handle to use for `stderr` (Nothing => use existing `stderr`)
-> IO ProcessHandle |

Runs a raw command, optionally specifying `Handle`s from which to take the `stdin`, `stdout` and `stderr` channels for the new process (otherwise these handles are inherited from the current process).

Any `Handle`s passed to `runProcess` are placed immediately in the closed state.

Note: consider using the more general `createProcess` instead of `runProcess`.

runInteractiveCommand :: String -> IO (Handle, Handle, Handle, ProcessHandle)

Runs a command using the shell, and returns `Handle`s that may be used to communicate with the process via its `stdin`, `stdout`, and `stderr` respectively. The `Handle`s are initially in binary mode; if you need them to be in text mode then use `hSetBinaryMode`.

runInteractiveProcess

Arguments

:: FilePath | Filename of the executable
-> [String] | Arguments to pass to the executable
-> Maybe FilePath | Optional path to the working directory
-> Maybe [(String, String)] | Optional environment (otherwise inherit)
-> IO (Handle, Handle, Handle, ProcessHandle) |

Runs a raw command, and returns `Handle`s that may be used to communicate with the process via its `stdin`, `stdout` and `stderr` respectively.

For example, to start a process and feed a string to its stdin:

       (inp,out,err,pid) <- runInteractiveProcess "..."
       forkIO (hPutStr inp str)

The `Handle`s are initially in binary mode; if you need them to be in text mode then use `hSetBinaryMode`.

readProcess

Arguments

:: FilePath | command to run
-> [String] | any arguments
-> String | standard input
-> IO String | stdout

readProcess forks an external process, reads its standard output strictly, blocking until the process terminates, and returns the output string.

Output is returned strictly, so this is not suitable for interactive applications.

Users of this function should compile with `-threaded` if they want other Haskell threads to keep running while waiting on the result of readProcess.

      > readProcess "date" [] []
      "Thu Feb  7 10:03:39 PST 2008\n"

The arguments are:

- The command to run, which must be in the $PATH, or an absolute path
- A list of separate command line arguments to the program
- A string to pass on the standard input to the program.

readProcessWithExitCode

Arguments

:: FilePath | command to run
-> [String] | any arguments
-> String | standard input
-> IO (ExitCode, String, String) | exitcode, stdout, stderr

readProcessWithExitCode creates an external process, reads its standard output and standard error strictly, waits until the process terminates, and then returns the `ExitCode` of the process, the standard output, and the standard error.

`readProcess` and `readProcessWithExitCode` are fairly simple wrappers around `createProcess`. Constructing variants of these functions is quite easy: follow the link to the source code to see how `readProcess` is implemented.

system :: String -> IO ExitCode

Computation `system cmd` returns the exit code produced when the operating system runs the shell command `cmd`.

This computation may fail with

- `PermissionDenied`: The process has insufficient privileges to perform the operation.
- `ResourceExhausted`: Insufficient resources are available to perform the operation.
- `UnsupportedOperation`: The implementation does not support system calls.

On Windows, `system` passes the command to the Windows command interpreter (`CMD.EXE` or `COMMAND.COM`), hence Unixy shell tricks will not work.

rawSystem :: String -> [String] -> IO ExitCode

The computation ``rawSystem` cmd args` runs the operating system command `cmd` in such a way that it receives as arguments the `args` strings exactly as given, with no funny escaping or shell meta-syntax expansion. It will therefore behave more portably between operating systems than `system`.

The return codes and possible failures are the same as for `system`.

# Process completion

waitForProcess :: ProcessHandle -> IO ExitCode

Waits for the specified process to terminate, and returns its exit code.

GHC Note: in order to call `waitForProcess` without blocking all the other threads in the system, you must compile the program with `-threaded`.

getProcessExitCode :: ProcessHandle -> IO (Maybe ExitCode)

This is a non-blocking version of `waitForProcess`. If the process is still running, `Nothing` is returned. If the process has exited, then ``Just` e` is returned where `e` is the exit code of the process.

terminateProcess :: ProcessHandle -> IO ()

Attempts to terminate the specified process. This function should not be used under normal circumstances - no guarantees are given regarding how cleanly the process is terminated. To check whether the process has indeed terminated, use `getProcessExitCode`.

On Unix systems, `terminateProcess` sends the process the SIGTERM signal. On Windows systems, the Win32 `TerminateProcess` function is called, passing an exit code of 1.

Note: on Windows, if the process was a shell command created by `createProcess` with `shell`, or created by `runCommand` or `runInteractiveCommand`, then `terminateProcess` will only terminate the shell, not the command itself. On Unix systems, both processes are in a process group and will be terminated together.