std/osproc (original) (raw)

Source Edit

This module implements an advanced facility for executing OS processes and process communication.

See also:

Types

ProcessOption = enum poEchoCmd,
poUsePath,

poEvalCommand,

poStdErrToStdOut,
poParentStreams,
poInteractive,

poDaemon

Options that can be passed to startProcess proc.Source Edit

Procs

proc close(p: Process) {....gcsafe, extern: "nosp$1", raises: [IOError, OSError], tags: [WriteIOEffect], forbids: [].}

When the process has finished executing, cleanup related handles.

**Warning:**If the process has not finished executing, this will forcibly terminate the process. Doing so may result in zombie processes and pty leaks.

Source Edit

proc countProcessors(): int {....gcsafe, extern: "nosp$1", raises: [], tags: [], forbids: [].}

Returns the number of the processors/cores the machine has. Returns 0 if it cannot be detected. It is implemented just calling cpuinfo.countProcessors.Source Edit

proc errorHandle(p: Process): FileHandle {....gcsafe, extern: "nosp$1", raises: [], tags: [], forbids: [].}

Returns p's error file handle for reading from.

**Warning:**The returned

FileHandle

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc errorStream(p: Process): Stream {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Returns p's error stream for reading from.

You cannot perform peek/write/setOption operations to this stream. Use peekableErrorStream proc if you need to peek stream.

**Warning:**The returned

Stream

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc execCmd(command: string): int {....gcsafe, extern: "nosp$1", tags: [ ExecIOEffect, ReadIOEffect, RootEffect], raises: [OSError], forbids: [].}

Executes command and returns its error code.

Standard input, output, error streams are inherited from the calling process. This operation is also often called system.

See also:

Example:

let errC = execCmd("nim c -r mytestfile.nim")

Source Edit

proc execCmdEx(command: string; options: set[ProcessOption] = {poStdErrToStdOut, poUsePath}; env: StringTableRef = nil; workingDir = ""; input = ""): tuple[ output: string, exitCode: int] {....raises: [OSError, IOError], tags: [ ExecIOEffect, ReadIOEffect, RootEffect], gcsafe, forbids: [].}

A convenience proc that runs the command, and returns its output and exitCode. env and workingDir params behave as for startProcess. If input.len > 0, it is passed as stdin.

Note: this could block if input.len is greater than your OS's maximum pipe buffer size.

See also:

Example:

var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") import std/[strutils, strtabs] stripLineEnd(result[0]) doAssert result == ("12", 0) doAssert execCmdEx("ls --nonexistent").exitCode != 0 when defined(posix): assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0)

Source Edit

proc execProcess(command: string; workingDir: string = ""; args: openArray[string] = []; env: StringTableRef = nil; options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): string {. ...gcsafe, extern: "nosp$1", raises: [OSError, IOError], tags: [ExecIOEffect, ReadIOEffect, RootEffect], forbids: [].}

A convenience procedure that executes command with startProcess and returns its output as a string.

**Warning:**This function uses

poEvalCommand

by default for backwards compatibility. Make sure to pass options explicitly.

See also:

Example:

let outp = execProcess("nim", args=["c", "-r", "mytestfile.nim"], options={poUsePath}) let outp_shell = execProcess("nim c -r mytestfile.nim")

Source Edit

proc execProcesses(cmds: openArray[string]; options = {poStdErrToStdOut, poParentStreams}; n = countProcessors(); beforeRunEvent: proc (idx: int) = nil; afterRunEvent: proc (idx: int; p: Process) = nil): int {. ...gcsafe, extern: "nosp$1", raises: [ValueError, OSError, IOError], tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect], effectsOf: [beforeRunEvent, afterRunEvent], ...forbids: [].}

Executes the commands cmds in parallel. Creates n processes that execute in parallel.

The highest (absolute) return value of all processes is returned. Runs beforeRunEvent before running each command.

Source Edit

proc inputHandle(p: Process): FileHandle {....gcsafe, raises: [], extern: "nosp$1", tags: [], forbids: [].}

Returns p's input file handle for writing to.

**Warning:**The returned

FileHandle

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc inputStream(p: Process): Stream {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Returns p's input stream for writing to.

**Warning:**The returned

Stream

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc outputHandle(p: Process): FileHandle {....gcsafe, extern: "nosp$1", raises: [], tags: [], forbids: [].}

Returns p's output file handle for reading from.

**Warning:**The returned

FileHandle

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc outputStream(p: Process): Stream {....gcsafe, extern: "nosp$1", raises: [IOError, OSError], tags: [], forbids: [].}

Returns p's output stream for reading from.

You cannot perform peek/write/setOption operations to this stream. Use peekableOutputStream proc if you need to peek stream.

**Warning:**The returned

Stream

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc peekableErrorStream(p: Process): Stream {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Returns p's error stream for reading from.

You can run peek operation to returned stream.

**Warning:**The returned

Stream

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc peekableOutputStream(p: Process): Stream {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Returns p's output stream for reading from.

You can peek returned stream.

**Warning:**The returned

Stream

should not be closed manually as it is closed when closing the Process

p

.

See also:

proc peekExitCode(p: Process): int {....gcsafe, extern: "nosp$1", raises: [OSError], tags: [], forbids: [].}

Return -1 if the process is still running. Otherwise the process' exit code.

On posix, if the process has exited because of a signal, 128 + signal number will be returned.

Source Edit

proc readLines(p: Process): (seq[string], int) {. ...raises: [OSError, IOError, ValueError], tags: [ReadIOEffect, TimeEffect], forbids: [].}

Convenience function for working with startProcess to read data from a background process.

See also:

Example:

const opts = {poUsePath, poDaemon, poStdErrToStdOut} var ps: seq[Process] for prog in ["a", "b"]: ps.add startProcess("nim", "", ["r", prog], nil, opts) for p in ps: let (lines, exCode) = p.readLines if exCode != 0: for line in lines: echo line p.close

Source Edit

proc resume(p: Process) {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Resumes the process p.

See also:

proc running(p: Process): bool {....gcsafe, extern: "nosp$1", raises: [OSError], tags: [], forbids: [].}

Returns true if the process p is still running. Returns immediately.Source Edit

proc startProcess(command: string; workingDir: string = ""; args: openArray[string] = []; env: StringTableRef = nil; options: set[ProcessOption] = {poStdErrToStdOut}): owned( Process) {....gcsafe, extern: "nosp$1", raises: [OSError, IOError], tags: [ExecIOEffect, ReadEnvEffect, RootEffect], forbids: [].}

Starts a process. Command is the executable file, workingDir is the process's working directory. If workingDir == "" the current directory is used (default). args are the command line arguments that are passed to the process. On many operating systems, the first command line argument is the name of the executable. args should not contain this argument! env is the environment that will be passed to the process. If env == nil (default) the environment is inherited of the parent process. options are additional flags that may be passed to startProcess. See the documentation of ProcessOption for the meaning of these flags.

You need to close the process when done.

Note that you can't pass any args if you use the option poEvalCommand, which invokes the system shell to run the specified command. In this situation you have to concatenate manually the contents of args to command carefully escaping/quoting any special characters, since it will be passed as is to the system shell. Each system/shell may feature different escaping rules, so try to avoid this kind of shell invocation if possible as it leads to non portable software.

Return value: The newly created process object. Nil is never returned, but OSError is raised in case of an error.

See also:

proc suspend(p: Process) {....gcsafe, extern: "nosp$1", tags: [], raises: [], forbids: [].}

Suspends the process p.

See also:

proc waitForExit(p: Process; timeout: int = -1): int {....gcsafe, extern: "nosp$1", raises: [OSError, ValueError], tags: [TimeEffect], forbids: [].}

Waits for the process to finish and returns p's error code.

**Warning:**Be careful when using

waitForExit

for processes created without

poParentStreams

because they may fill output buffers, causing deadlock.

On posix, if the process has exited because of a signal, 128 + signal number will be returned.

**Warning:**When working with

timeout

parameters, remember that the value is typically expressed in milliseconds, and ensure that the correct unit of time is used to avoid unexpected behavior.

Source Edit

Iterators

iterator lines(p: Process; keepNewLines = false): string {. ...raises: [OSError, IOError, ValueError], tags: [ReadIOEffect, TimeEffect], forbids: [].}

Convenience iterator for working with startProcess to read data from a background process.

See also:

Example:

const opts = {poUsePath, poDaemon, poStdErrToStdOut} var ps: seq[Process] for prog in ["a", "b"]: ps.add startProcess("nim", "", ["r", prog], nil, opts) for p in ps: var i = 0 for line in p.lines: echo line i.inc if i > 100: break p.close

Source Edit