Run commands and read the process environment. The function exec runs off the main loop and returns a promise. The environment and working-directory accessors are synchronous.
-
process.exec(command, options?)→ A promise resolving to a table{stdout, stderr, code}. The command runs through the platform shell —/bin/sh -con POSIX andcmd.exe /con Windows — so shell features like pipes and redirection work with each shell's own syntax. Both streams are captured binary-safe up to a combined 64 MiB cap, past which the child is killed so an endless producer cannot exhaust host memory. The fieldcodeis the exit status. A child killed by a POSIX signal reports128 + signal(a cap overrun is137), while a terminated Windows process reports its own termination code. -
The option
options.timeoutMsbounds how long the command may run. When it passes the deadline the child is killed and the promise rejects rather than resolving with a partial result, so an overrun can never be mistaken for a normal exit. Without it the call waits as long as the child lives, matchingchild_process.execin Node andsubprocess.runin Python. A negative value is refused at the call.Each
execoccupies one thread of the I/O pool for its whole run, and that pool also servesfsand the HTTP client. A command that may hang — anything reaching the network, or a tool that can wait on a lock or a prompt — should carry atimeoutMs, or enough of them will starve the pool the rest of the runtime depends on.local result, err = process.exec("curl -s https://example.com", { timeoutMs = 5000 }):await() if err then -- The command overran its deadline and was killed end
-
process.env→ A table mapping each environment variable name to its value, captured when the module is required. -
process.getenv(name, default?)→ The value ofname, ordefault(ornil) when it is unset. -
process.cwd()→ The current working directory as a string. -
process.argv→ An array of the script arguments. This is the same data as the globalargtable, normalized to a 1-based array that dropsarg[0](the script path) and the host options, leaving just the arguments your script received. -
process.available→ Holdstruewhen this build can run commands,falseon the stub builds (iOS, tvOS, watchOS, visionOS, and WebAssembly) whereprocess.execrejects with"not available in this build".
Commands are not sandboxed. Confine untrusted input before passing it here. A command containing a null byte is rejected rather than silently truncated. On builds without process support (such as the browser build) process.exec rejects with "not available in this build".
-- Runs a command and prints its capture, environment, and working directory.
local async = require("async")
local process = require("process")
async.run(function()
local result, err = process.exec("echo varn && echo oops 1>&2"):await()
assert(not err, err)
print("code: " .. result.code)
print("stdout: " .. result.stdout)
print("stderr: " .. result.stderr)
print("home: " .. process.getenv("HOME", "(unset)"))
print("cwd: " .. process.cwd())
if #process.argv > 0 then
print("argv: " .. table.concat(process.argv, " "))
end
end)-- Runs a successful and a failing command and prints env, cwd, and argv.
local async = require("async")
local process = require("process")
if not process.available then
print("process not available")
return
end
async.run(function()
local ok = process.exec("echo hello"):await()
print("ok code: " .. ok.code)
print("ok stdout: " .. ok.stdout)
local fail = process.exec("exit 3"):await()
print("fail code: " .. fail.code)
print("path: " .. process.getenv("PATH", "(unset)"))
print("missing: " .. process.getenv("VARN_NOPE", "(default)"))
print("env type: " .. type(process.env))
print("cwd: " .. process.cwd())
print("argv: " .. table.concat(process.argv, " "))
print("process status and argv ok")
end)On native builds commands run through fork + execl("/bin/sh", ...) with pipes for stdout and stderr, capturing each stream until end of file. The browser build uses a stub driver that rejects exec.