Skip to Content

Process

Introduction

import 'process';

The process module provides command-line arguments, exit codes, standard input and output, and a way to run other programs.

import 'process'; String[] args = process.getArgs(); if (args.length == 0) { process.stderr.write("usage: tool <file>\n"); process.exit(1); }

Notes

  • stdout is the program’s normal output. stderr is for diagnostics that should stay separate from that output.
  • process.stdout.write and process.stderr.write write text exactly as given and do not add a newline.
  • Output is sent on in blocks, and at exit. A program that writes a prompt and then waits for a reply must flush first.
  • Standard-input reads are fallible and can be handled with catch. Reaching the end of input is not an error.
  • process.child.run starts another program without using a shell. It returns a future so the caller chooses when to wait.

process.child.run returns a process.ChildRunResult:

FieldTypeDescription
stdoutbyte[]Everything the child wrote to standard output.
stderrbyte[]Everything the child wrote to standard error.
codeintThe child’s exit code.
usageprocess.ChildUsage?What the child cost, or null where the platform does not report it.

process.ChildUsage is what the operating system charged the child:

FieldTypeDescription
peakMemoryintThe most memory it held at once, in bytes.
userTimeDurationCPU time spent running its own code.
systemTimeDurationCPU time the system spent on its behalf.
minorFaultsintPage faults served without a device read.
majorFaultsintPage faults that needed a read.
blockReadsintBlock input operations.
blockWritesintBlock output operations.
voluntarySwitchesintTimes it gave up the CPU to wait for something.
involuntarySwitchesintTimes it was taken off the CPU.
import 'process'; process.ChildRunResult r = await process.child.run("make", ["all"]); process.ChildUsage? used = r.usage; if (used != null) { print(used.peakMemory / 1048576, "MB peak,", used.userTime + used.systemTime, "ms of CPU"); }

The two times are Durations, so they count milliseconds; a child that used less than one reports none.

Its optional third argument is a process.ChildRunOptions:

FieldTypeDescription
stdinbyte[]?Bytes provided as the child’s standard input.
cwdString?Working directory for the child.
envMap<String, String>?Environment variables to add or replace.
clearEnvbool?Use only env instead of inheriting the current environment.
inheritbool?Let the child use this process’s standard streams.

process.getArgs()

String[] process.getArgs()

Returns the command-line arguments in order, without the program’s own name. A program started without arguments receives an empty array.

Each call returns a new array.

import 'process'; // $ nio run tool.nio build main.nio String[] args = process.getArgs(); print(args.length); // 2 print(args[0]); // build print(args[1]); // main.nio

process.exit()

void process.exit(int code)

Ends the program immediately with the given exit code. Code after the call and pending async work do not run.

Use 0 for success and a value from 1 to 255 for failure.

import 'process'; bool valid = false; if (!valid) { process.stderr.write("invalid input\n"); process.exit(1); } print("ready");

process.stdout.write()

void process.stdout.write(String text)

Writes text to standard output without adding a newline.

Use string.fromByteArray to write a byte array.

import 'process'; process.stdout.write("loading"); process.stdout.write("...\n"); print("done");

process.stderr.write()

void process.stderr.write(String text)

Writes text to standard error without adding a newline.

import 'process'; process.stderr.write("warning: using defaults\n"); print("result"); // written to stdout

process.stdout.flush()

void process.stdout.flush() void process.stderr.flush()

Sends everything written so far on to whatever the stream is connected to.

Output is normally held back and sent on in blocks — at each newline when the stream is a terminal, and only once several thousand bytes have collected when it is a pipe or a file. This is invisible to a program that runs and ends, because everything left is sent on at exit, in order.

It matters in one case: a program that writes something and then waits for a reply to it. Under a pipe the request is still in this program’s buffer, so the other side has nothing to answer and both wait forever. Write, flush, then read.

import 'process'; process.stdout.write("name? "); process.stdout.flush(); // without this, nothing is asked String? answer = process.stdin.readLine() catch null;

process.stderr.flush() is the same for standard error, which may be held to the end of a line — enough to strand a prompt written without one.

process.stdin.read()

byte[] process.stdin.read()

Reads all remaining standard input as bytes. It returns an empty array when the input has ended and is fallible when the input cannot be read.

The input is consumed by the call.

import 'process'; import 'string'; byte[] input = process.stdin.read() catch []; String text = string.fromByteArray(input); process.stdout.write(string.toUpperCaseAscii(text));

process.stdin.readBytes()

byte[] process.stdin.readBytes(int n)

Reads up to n bytes. The result is shorter than n only when the input ended first, and empty exactly at the end of input — which is how “the stream is finished” is told from “the stream had less than I asked for”. A negative n is a runtime error, not an Error.

Use it for input whose shape is a count rather than a delimiter. read() consumes everything, and readLine() needs a "\n", so neither can read a framed message — one that states its length and then gives that many bytes with nothing between it and the next one.

Because a short read only ever means the input ended, a caller that needs exactly n bytes loops:

import 'process'; import 'array'; byte[] exactly(int n) { byte[] out = []; while (out.length < n) { byte[] chunk = process.stdin.readBytes(n - out.length) catch []; if (chunk.length == 0) { return out; // the input ended early } forEach(chunk, b) { array.push(out, b); } } return out; }

process.stdin.readLine()

String? process.stdin.readLine()

Reads the next line without its line ending. Both LF and CRLF endings are removed. The final line is returned even when it has no line ending.

The result is null at the end of input. Reading is fallible, so a loop can handle an error and end-of-input together:

import 'process'; String? line = process.stdin.readLine() catch null; while (line != null) { process.stdout.write("> " + line + "\n"); line = process.stdin.readLine() catch null; }

process.child.run()

Future<process.ChildRunResult!> process.child.run( String command, String[] args ) Future<process.ChildRunResult!> process.child.run( String command, String[] args, process.ChildRunOptions options )

Starts another program and returns a future for its result. The command is found through PATH, or used as a path when it contains a separator.

Arguments are passed exactly as written. No shell quoting, wildcard expansion, pipes, or redirection is performed.

Failure to start the program is carried by the future, so catch belongs on await. A program that starts and exits with a nonzero code still returns a normal result; inspect result.code.

By default, the child receives empty standard input and its output is collected in the result. The options record can provide input, change its directory or environment, or share this process’s streams. With { inherit: true }, the returned stdout and stderr arrays are empty and any stdin option is ignored.

The call returns immediately, so multiple children can be started before they are awaited.

import 'process'; import 'string'; Future<process.ChildRunResult!> pending = process.child.run( "git", ["status", "--short"], { cwd: "project", env: { "NO_COLOR": "1" } } ); process.ChildRunResult? result = await pending catch e { process.stderr.write(e.message + "\n"); }; if (result != null) { process.stdout.write(string.fromByteArray(result.stdout)); if (result.code != 0) { process.stderr.write(string.fromByteArray(result.stderr)); } }