# Process APIs

### Process APIs

The standard library gives access to process information through `std.process`.

A process can inspect its command-line arguments.

```zig
const std = @import("std");

pub fn main() !void {
    var args = try std.process.argsWithAllocator(std.heap.page_allocator);
    defer args.deinit();

    while (args.next()) |arg| {
        std.debug.print("{s}\n", .{arg});
    }
}
```

Run it:

```sh
zig run main.zig -- one two three
```

The output is similar to:

```text
/path/to/main
one
two
three
```

The first argument is the program name.

The remaining arguments are the words passed after `--`.

The `--` separates arguments for `zig run` from arguments for the program.

`argsWithAllocator` uses an allocator because argument handling may need memory on some platforms.

```zig
var args = try std.process.argsWithAllocator(allocator);
```

The iterator must be released.

```zig
defer args.deinit();
```

For small examples, the page allocator is enough.

```zig
std.heap.page_allocator
```

For larger programs, use the same allocator policy as the rest of the program.

A simple argument parser can be written directly.

```zig
const std = @import("std");

pub fn main() !void {
    var args = try std.process.argsWithAllocator(std.heap.page_allocator);
    defer args.deinit();

    _ = args.next();

    const name = args.next() orelse "world";

    std.debug.print("hello, {s}\n", .{name});
}
```

Run it:

```sh
zig run main.zig -- zig
```

The output is:

```text
hello, zig
```

Run it without an argument:

```sh
zig run main.zig
```

The output is:

```text
hello, world
```

Environment variables are also available through `std.process`.

```zig
const std = @import("std");

pub fn main() !void {
    const home = std.process.getEnvVarOwned(
        std.heap.page_allocator,
        "HOME",
    ) catch |err| switch (err) {
        error.EnvironmentVariableNotFound => {
            std.debug.print("HOME is not set\n", .{});
            return;
        },
        else => return err,
    };
    defer std.heap.page_allocator.free(home);

    std.debug.print("{s}\n", .{home});
}
```

`getEnvVarOwned` returns an allocated string.

The caller owns it and must free it.

```zig
defer allocator.free(home);
```

The environment variable may not exist, so the error is handled explicitly.

The process module also provides access to the current working directory.

```zig
const std = @import("std");

pub fn main() !void {
    var buffer: [std.fs.max_path_bytes]u8 = undefined;

    const path = try std.process.getCwd(buffer[0..]);

    std.debug.print("{s}\n", .{path});
}
```

The buffer is supplied by the caller.

The function writes the current path into the buffer and returns the slice that was used.

This avoids allocation.

A program can also exit with a status code.

```zig
const std = @import("std");

pub fn main() void {
    std.process.exit(1);
}
```

Exit status `0` means success.

A nonzero status means failure by convention.

For command-line tools, this matters. Shell scripts and build systems inspect exit codes.

A program can use this pattern:

```zig
const std = @import("std");

pub fn main() !void {
    const ok = false;

    if (!ok) {
        std.debug.print("error: operation failed\n", .{});
        std.process.exit(1);
    }
}
```

The program prints a diagnostic and exits with failure.

Child processes are also managed through the standard library.

```zig
const std = @import("std");

pub fn main() !void {
    var child = std.process.Child.init(
        &.{ "zig", "version" },
        std.heap.page_allocator,
    );

    const term = try child.spawnAndWait();

    std.debug.print("{any}\n", .{term});
}
```

`Child.init` takes an argument vector.

```zig
&.{ "zig", "version" }
```

The first string is the program to run.

The rest are its arguments.

`spawnAndWait` starts the process and waits for it to finish.

The result describes how the child ended.

A more useful program captures output.

```zig
const std = @import("std");

pub fn main() !void {
    const result = try std.process.Child.run(.{
        .allocator = std.heap.page_allocator,
        .argv = &.{ "zig", "version" },
    });
    defer std.heap.page_allocator.free(result.stdout);
    defer std.heap.page_allocator.free(result.stderr);

    std.debug.print("stdout: {s}", .{result.stdout});
    std.debug.print("stderr: {s}", .{result.stderr});
}
```

`Child.run` allocates buffers for standard output and standard error.

The caller frees both.

```zig
defer allocator.free(result.stdout);
defer allocator.free(result.stderr);
```

This makes process execution convenient while keeping ownership visible.

The process API follows the same rules as the rest of Zig.

Arguments are explicit.

Allocation is explicit.

Failure is explicit.

Exit status is explicit.

Exercise 14-25. Print all command-line arguments.

Exercise 14-26. Write a program that accepts a name and prints a greeting.

Exercise 14-27. Read an environment variable and handle the missing case.

Exercise 14-28. Run `zig version` as a child process and print its output.

