Call and spawn new process with stdin

I want to call a process and provide stdin and get stdout how to do that?

The pipe gives and takes a file and I do not know how to read it or create one from just hard coded string, this is somewhat pseudo code, any ideas how to make it work:

const std = @import("std");

pub fn main(init: std.process.Init) !void {
	const io = init.io;
	const input = "Hello from zig";
    var child = try std.process.spawn(
        io,
        .{
            .argv = &[_][]const u8{"/bin/cat"},
            .stdin = .pipe,
            .stdout = .pipe,
        },
    );
    child.stdin = input
    var stdout_buffer: [1024]u8 = undefined;
    if (child.stdout) |stdout| {
		_ = try stdout.readPositionalAll(io, &stdout_buffer, 1024);
    }
    _ = try child.wait(io);
	stdout_buffer == input
}

A dangerous working snippet for illustration purposes. You still need check optional entries here.

I did need to read the standard library example to understand this. To be able to pass the stdin you need to write to child.stdin using the writer interface, and after that you need to close it to “send EOF” otherwise the cat process get stuck waiting for it.

const std = @import("std");

pub fn main(init: std.process.Init) !void {
    const io = init.io;
    const input = "Hello from zig";
    var child = try std.process.spawn(
        io,
        .{
            .argv = &[_][]const u8{"/bin/cat"},
            .stdin = .pipe,
            .stdout = .pipe,
            .stderr = .ignore,
        },
    );

    var writer = child.stdin.?.writer(io, &.{});
    try writer.interface.writeAll(input);
    child.stdin.?.close(io);
    child.stdin = null;

    var stdout_buffer: [512]u8 = undefined;
    var stdout_reader: std.Io.File.Reader = .initStreaming(child.stdout.?, io, &stdout_buffer);
    const stdout = &stdout_reader.interface;
    stdout.readSliceAll(&stdout_buffer) catch |err| switch (err) {
        error.EndOfStream => {},
        else => return err
    };

    const term = try child.wait(io);

    if (term.exited != 0) {
        std.debug.print("process failed, exit code {}", .{ term.exited });
        return;
    }

    std.debug.print("return: {s}", .{ stdout_buffer[0..stdout_reader.pos] });
}

Some of things I didn’t understand: I tried to get the stdout.bufferedLen but it’s always returning 0 (My guess is this zeroed after child wait but I need to dig more into this), so I used stdout_reader.pos instead to delimiter until where I should read the output, but I believe this is not the ideal nor safe.