Process handling
| Runs program directly | Runs shell command | |
|---|---|---|
| Low-level process creation | spawnProcess | spawnShell |
| Automatic input/output redirection using pipes | pipeProcess | pipeShell |
| Execute and wait for completion, collect output | execute | executeShell |
Other functionality
Sourcestd/process.d
NoteMost of the functionality in this module is not available on iOS, tvOSand watchOS. The only functions available on those platforms are:environment,thisProcessID andthisThreadID.
environment;opIndex(scope const(char)[]name);name.auto path = environment["PATH"];
get(scope const(char)[]name, stringdefaultValue = null);name, or a default value if the variable doesn't exist.auto sh = environment.get("SHELL","/bin/sh");This function is also useful in checking for the existence of an environment variable.
auto myVar = environment.get("MYVAR");if (myVarisnull){// Environment variable doesn't exist.// Note that we have to use 'is' for the comparison, since// myVar == null is also true if the variable exists but is// empty.}
const(char)[]name | name of the environment variable to retrieve |
stringdefaultValue | default value to return if the environment variable doesn't exist. |
opIndexAssign(return scope inout char[]value, scope const(char)[]name);value to the environment variable with the givenname. Ifvalue is null the variable is removed from environment.environment["foo"] ="bar";
NoteOn some platforms, modifying environment variables may not be allowed in multi-threaded programs. See e.g.glibc.
remove(scope const(char)[]name);name.NoteOn some platforms, modifying environment variables may not be allowed in multi-threaded programs. See e.g.glibc.
opBinaryRight(string op : "in")(scope const(char)[]name);Example
// good usageif ("MY_ENV_FLAG"in environment) doSomething();// bad usageif ("MY_ENV_VAR"in environment) doSomething(environment["MY_ENV_VAR"]);// do this insteadif (auto var = environment.get("MY_ENV_VAR")) doSomething(var);
toAA();Windows specificWhile Windows environment variable names are case insensitive, D's built-in associative arrays are not. This function will store all variable names in uppercase (e.g.PATH).
thisProcessID();Example
writefln("Current process ID: %d",thisProcessID);
thisThreadID();Example
writefln("Current thread ID: %s",thisThreadID);
spawnProcess(scope const(char[])[]args, Filestdin = std.stdio.stdin, Filestdout = std.stdio.stdout, Filestderr = std.stdio.stderr, const string[string]env = null, Configconfig = Config.none, scope const char[]workDir = null);spawnProcess(scope const(char[])[]args, const string[string]env, Configconfig = Config.none, scope const(char)[]workDir = null);spawnProcess(scope const(char)[]program, Filestdin = std.stdio.stdin, Filestdout = std.stdio.stdout, Filestderr = std.stdio.stderr, const string[string]env = null, Configconfig = Config.none, scope const(char)[]workDir = null);spawnProcess(scope const(char)[]program, const string[string]env, Configconfig = Config.none, scope const(char)[]workDir = null);Command lineThere are four overloads of this function. The first two take an arrayof strings,args, which should contain the program name as thezeroth element and any command-line arguments in subsequent elements.The third and fourth versions are included for convenience, and may beused when there are no command-line arguments. They take a single string,program, which specifies the program name.
args[0] orprogram,spawnProcess will search for the program in a platform-dependentmanner. On POSIX systems, it will look for the executable in thedirectories listed in the PATH environment variable, in the orderthey are listed. On Windows, it will search for the executable inthe following sequence:// Run an executable called "prog" located in the current working// directory:auto pid =spawnProcess("./prog");scope(exit) wait(pid);// We can do something else while the program runs. The scope guard// ensures that the process is waited for at the end of the scope....// Run DMD on the file "myprog.d", specifying a few compiler switches:auto dmdPid =spawnProcess(["dmd","-O","-release","-inline","myprog.d" ]);if (wait(dmdPid) != 0) writeln("Compilation failed!");
Environment variablesBy default, the child process inherits the environment of the parentprocess, along with any additional variables specified in theenvparameter. If the same variable exists in both the parent's environmentand inenv, the latter takes precedence.
config, the childprocess willnot inherit the parent's environment. Its entireenvironment will then be determined byenv.wait(spawnProcess("myapp", ["foo" :"bar"], Config.newEnv));
Standard streamsThe optional argumentsstdin,stdout andstderr maybe used to assign arbitrarystd.stdio.File objects as the standardinput, output and error streams, respectively, of the child process. Theformer must be opened for reading, while the latter two must be opened forwriting. The default is for the child process to inherit the standardstreams of its parent.
// Run DMD on the file myprog.d, logging any error messages to a// file named errors.log.auto logFile = File("errors.log","w");auto pid =spawnProcess(["dmd","myprog.d"], std.stdio.stdin, std.stdio.stdout, logFile);if (wait(pid) != 0) writeln("Compilation failed. See errors.log for details.");Note that if you pass aFile object that isnotone of the standard input/output/error streams of the parent process,that stream will by default beclosed in the parent process whenthis function returns. See theConfig documentation below forinformation about how to disable this behaviour.Beware of buffering issues when passingFile objects to
spawnProcess. The child process will inherit the low-level rawread/write offset associated with the underlying file descriptor, butit will not be aware of any buffered data. In cases where this matters(e.g. when a file should be aligned before being passed on to thechild process), it may be a good idea to use unbuffered streams, or atleast ensure all relevant buffers are flushed.const(char[])[]args | An array which contains the program name as the zeroth element and any command-line arguments in the following elements. |
Filestdin | The standard input stream of the child process. This can be anystd.stdio.File that is opened for reading. By default the child process inherits the parent's input stream. |
Filestdout | The standard output stream of the child process. This can be anystd.stdio.File that is opened for writing. By default the child process inherits the parent's output stream. |
Filestderr | The standard error stream of the child process. This can be anystd.stdio.File that is opened for writing. By default the child process inherits the parent's error stream. |
string[string]env | Additional environment variables for the child process. |
Configconfig | Flags that control process creation. SeeConfig for an overview of available flags. |
char[]workDir | The working directory for the new process. By default the child process inherits the parent's working directory. |
args is empty.spawnShell(scope const(char)[]command, Filestdin = std.stdio.stdin, Filestdout = std.stdio.stdout, Filestderr = std.stdio.stderr, scope const string[string]env = null, Configconfig = Config.none, scope const(char)[]workDir = null, scope stringshellPath = nativeShell);spawnShell(scope const(char)[]command, scope const string[string]env, Configconfig = Config.none, scope const(char)[]workDir = null, scope stringshellPath = nativeShell);command is passed verbatim to the shell, and is thereforesubject to its rules about command structure, argument/filename quotingand escaping of special characters.The path to the shell executable defaults tonativeShell.In all other respects this function works just likespawnProcess.Please refer to thespawnProcess documentation for descriptionsof the other function parameters, the return value and any exceptionsthat may be thrown.// Run the command/program "foo" on the file named "my file.txt", and// redirect its output into foo.log.auto pid =spawnShell(`foo "my file.txt" > foo.log`);wait(pid);
Config;Example
auto logFile = File("myapp_error.log","w");// Start program, suppressing the console window (Windows only),// redirect its error stream to logFile, and leave logFile open// in the parent process as well.auto pid = spawnProcess("myapp", stdin, stdout, logFile,Config.retainStderr |Config.suppressConsole);scope(exit){auto exitCode = wait(pid); logFile.writeln("myapp exited with code ", exitCode); logFile.close();}
Flags: int;flags;newEnvretainStdinretainStdoutretainStderrsuppressConsolesuppressConsole has no effect.inheritFDsinheritFDs to prevent this.detachedstderrPassThroughnone;newEnv;retainStdin;retainStdout;retainStderr;suppressConsole;inheritFDs;detached;stderrPassThrough;opUnary(string op)()opBinary(string op)(Configother)other.flags"))));opOpAssign(string op)(Configother)other.flags"))));preExecFunction;preExecDelegate;Pid;processID() const;osHandle();wait(Pidpid);pid to terminate, and returnsits exit status.POSIX specificIf the process is terminated by a signal, this function returns anegative number whose absolute value is the signal number.Since POSIX restricts normal exit codes to the range 0-255, anegative return value will always indicate termination by signal.Signal codes are defined in thecore.sys.posix.signal module(which corresponds to thesignal.h POSIX header).
ExampleSee thespawnProcess documentation.
waitTimeout(Pidpid, Durationtimeout);pid terminates or theelapsed time exceeds the given timeout.ExampleSee thespawnProcess documentation.
tryWait(Pidpid);pid has already terminated,tryWait has the exact same effect aswait.In this case, it returns a tuple where theterminated fieldis set totrue and thestatus field has the sameinterpretation as the return value ofwait.If the process hasnot yet terminated, this function differsfromwait in that does not wait for this to happen, but insteadreturns immediately. Theterminated field of the returnedtuple will then be set tofalse, while thestatus fieldwill always be 0 (zero).wait ortryWait should then becalled again on the samePid at some later time; not only toget the exit code, but also to avoid the process becoming a "zombie"when it finally terminates. (Seewait for details).Example
autopid = spawnProcess("dmd myapp.d");scope(exit) wait(pid);...auto dmd =tryWait(pid);if (dmd.terminated){if (dmd.status == 0) writeln("Compilation succeeded!");else writeln("Compilation failed");}else writeln("Still compiling...");...Note that in this example, the firstwait call will have noeffect if the process has already terminated by the time
tryWaitis called. In the opposite case, however, thescope statementensures that we always wait for the process if it hasn't terminatedby the time we reach the end of the scope.kill(Pidpid);kill(Pidpid, intcodeOrSignal);pid.codeOrSignal,is highly platform dependent. Details are given below. Common to allplatforms is that this function onlyinitiates termination of the process,and returns immediately. It does not wait for the process to end,nor does it guarantee that the process does in fact get terminated.Always callwait to wait for a process to complete, even ifkillhas been called on it.Windows specificThe process will beforcefully and abruptly terminated. IfcodeOrSignal is specified, itmust be a nonnegative number which will be used as the exit code of the process.If not, the process wil exit with code 1. Do not usecodeOrSignal = 259,as this is a special value (aka.STILL_ACTIVE)used by Windows to signal that a process has in factnot terminated yet.
autopid = spawnProcess("some_app");kill(pid, 10);assert(wait(pid) == 10);
POSIX specificAsignal will be sent tothe process, whose value is given bycodeOrSignal. Depending on thesignal sent, this may or may not terminate the process. Symbolic constantsfor variousPOSIX signals are defined incore.sys.posix.signal, which corresponds to thesignal.h POSIX header. IfcodeOrSignal is omitted, theSIGTERM signal will be sent. (This matches the behaviour of the_kill shell command.)
import core.sys.posix.signal : SIGKILL;autopid = spawnProcess("some_app");kill(pid, SIGKILL);assert(wait(pid) == -SIGKILL);// Negative return value on POSIX!
pipe();auto p =pipe();p.writeEnd.writeln("Hello World");p.writeEnd.flush();assert(p.readEnd.readln().chomp() =="Hello World");Pipes can, for example, be used for interprocess communicationby spawning a new process and passing one end of the pipe tothe child, while the parent uses the other end.(See alsopipeProcess andpipeShell for an easierway of doing this.)
// Use cURL to download the dlang.org front page, pipe its// output to grep to extract a list of links to ZIP files,// and write the list to the file "D downloads.txt":auto p =pipe();auto outFile = File("D downloads.txt","w");auto cpid = spawnProcess(["curl","http://dlang.org/download.html"], std.stdio.stdin, p.writeEnd);scope(exit) wait(cpid);auto gpid = spawnProcess(["grep","-o",`http://\S*\.zip`], p.readEnd, outFile);scope(exit) wait(gpid);
Pipe;readEnd();writeEnd();close();pipeProcess(scope const(char[])[]args, Redirectredirect = Redirect.all, const string[string]env = null, Configconfig = Config.none, scope const(char)[]workDir = null);pipeProcess(scope const(char)[]program, Redirectredirect = Redirect.all, const string[string]env = null, Configconfig = Config.none, scope const(char)[]workDir = null);pipeShell(scope const(char)[]command, Redirectredirect = Redirect.all, const string[string]env = null, Configconfig = Config.none, scope const(char)[]workDir = null, stringshellPath = nativeShell);pipeProcess andpipeShell are convenient wrappers aroundspawnProcess andspawnShell, respectively, andautomate the task of redirecting one or more of the child process'standard streams through pipes. Like the functions they wrap,these functions return immediately, leaving the child process toexecute in parallel with the invoking process. It is recommendedto always callwait on the returnedProcessPipes.pid,as detailed in the documentation forwait.Theargs/program/command,env andconfigparameters are forwarded straight to the underlying spawn functions,and we refer to their documentation for details.const(char[])[]args | An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (SeespawnProcess for details.) |
const(char)[]program | The program name,without command-line arguments. (SeespawnProcess for details.) |
const(char)[]command | A shell command which is passed verbatim to the command interpreter. (SeespawnShell for details.) |
Redirectredirect | Flags that determine which streams are redirected, and how. SeeRedirect for an overview of available flags. |
string[string]env | Additional environment variables for the child process. (SeespawnProcess for details.) |
Configconfig | Flags that control process creation. SeeConfig for an overview of available flags, and note that theretainStd... flags have no effect in this function. |
const(char)[]workDir | The working directory for the new process. By default the child process inherits the parent's working directory. |
stringshellPath | The path to the shell to use to run the specified program. By default this isnativeShell. |
Example
// my_application writes to stdout and might write to stderrauto pipes =pipeProcess("my_application", Redirect.stdout | Redirect.stderr);scope(exit) wait(pipes.pid);// Store lines of output.string[] output;foreach (line; pipes.stdout.byLine) output ~= line.idup;// Store lines of errors.string[] errors;foreach (line; pipes.stderr.byLine) errors ~= line.idup;// sendmail expects to read from stdinpipes =pipeProcess(["/usr/bin/sendmail","-t"], Redirect.stdin);pipes.stdin.writeln("To: you");pipes.stdin.writeln("From: me");pipes.stdin.writeln("Subject: dlang");pipes.stdin.writeln("");pipes.stdin.writeln(message);// a single period tells sendmail we are finishedpipes.stdin.writeln(".");// but at this point sendmail might not see it, we need to flushpipes.stdin.flush();// sendmail happens to exit on ".", but some you have to close the file:pipes.stdin.close();// otherwise this wait will wait foreverwait(pipes.pid);
Redirect: int;stdinstdoutstderrallstderrToStdoutstdoutToStderrProcessPipes;pid();stdin();stdout();stderr();execute(scope const(char[])[]args, const string[string]env = null, Configconfig = Config.none, size_tmaxOutput = size_t.max, scope const(char)[]workDir = null);execute(scope const(char)[]program, const string[string]env = null, Configconfig = Config.none, size_tmaxOutput = size_t.max, scope const(char)[]workDir = null);executeShell(scope const(char)[]command, const string[string]env = null, Configconfig = Config.none, size_tmaxOutput = size_t.max, scope const(char)[]workDir = null, stringshellPath = nativeShell);execute andexecuteShell start a new process usingspawnProcess andspawnShell, respectively, and waitfor the process to complete before returning. The functions capturewhat the child process prints to both its standard output andstandard error streams, and return this together with its exit code.auto dmd =execute(["dmd","myapp.d"]);if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);auto ls =executeShell("ls -l");if (ls.status != 0) writeln("Failed to retrieve file listing");else writeln(ls.output);The
args/program/command,env andconfigparameters are forwarded straight to the underlying spawn functions,and we refer to their documentation for details.const(char[])[]args | An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (SeespawnProcess for details.) |
const(char)[]program | The program name,without command-line arguments. (SeespawnProcess for details.) |
const(char)[]command | A shell command which is passed verbatim to the command interpreter. (SeespawnShell for details.) |
string[string]env | Additional environment variables for the child process. (SeespawnProcess for details.) |
Configconfig | Flags that control process creation. SeeConfig for an overview of available flags, and note that theretainStd... flags have no effect in this function. |
size_tmaxOutput | The maximum number of bytes of output that should be captured. |
const(char)[]workDir | The working directory for the new process. By default the child process inherits the parent's working directory. |
stringshellPath | The path to the shell to use to run the specified program. By default this isnativeShell. |
POSIX specificIf the process is terminated by a signal, thestatus field ofthe return value will contain a negative number whose absolutevalue is the signal number. (Seewait for details.)
ProcessException:object.Exception;userShell();userShell returns the contents of the SHELL environmentvariable, if it exists and is non-empty. Otherwise, it returns the result ofnativeShell.nativeShell();escapeShellCommand(scope const(char[])[]args...);string url ="http://dlang.org/";executeShell(escapeShellCommand("wget", url,"-O","dlang-index.html"));
escapeShellCommand andescapeShellFileName results to use shell redirection orpiping operators.executeShell(escapeShellCommand("curl","http://dlang.org/download.html") ~"|" ~escapeShellCommand("grep","-o",`http://\S*\.zip`) ~">" ~ escapeShellFileName("D download links.txt"));
escapeWindowsArgument(scope const(char)[]arg);escapeShellFileName(scope const(char)[]fileName);execv(in stringpathname, in string[]argv);execve(in stringpathname, in string[]argv, in string[]envp);execvp(in stringpathname, in string[]argv);execvpe(in stringpathname, in string[]argv, in string[]envp);pathname, with the arguments inargv.argv is the command being executed, i.e.argv[0] == pathname. The 'p' versions ofexec search the PATH environment variable for pathname. The 'e' versions additionally take the new process' environment variables as an array of strings of the form key=value. Does not return on success (the current process will have been replaced). Returns -1 on failure with no indication of the underlying error.Windows specific These functions are only supported on POSIX platforms, as the Windows operating systems do not provide the ability to overwrite the current process image with another. In single-threaded programs it is possible to approximate the effect ofexecv* by usingspawnProcess and terminating the current process once the child process has returned. For example:
auto commandLine = ["program","arg1","arg2" ];version (Posix){execv(commandLine[0], commandLine);thrownew Exception("Failed to execute program");}elseversion (Windows){import core.stdc.stdlib : _Exit; _Exit(wait(spawnProcess(commandLine)));}This is, however, NOT equivalent to POSIX'
execv*. For one thing, the executed program is started as a separate process, with all this entails. Secondly, in a multithreaded program, other threads will continue to do work while the current thread is waiting for the child process to complete. A better option may sometimes be to terminate the current program immediately after spawning the child process. This is the behaviour exhibited by the__exec functions in Microsoft's C runtime library, and it is how D's now-deprecated Windowsexecv* functions work. Example:auto commandLine = ["program","arg1","arg2" ];version (Posix){execv(commandLine[0], commandLine);thrownew Exception("Failed to execute program");}elseversion (Windows){ spawnProcess(commandLine);import core.stdc.stdlib : _exit; _exit(0);}
browse(scope const(char)[]url);