# A custom build.zig command to run system commands and see their output

**URL:** <https://ziggit.dev/t/a-custom-build-zig-command-to-run-system-commands-and-see-their-output/10212>\
**Category:** Help\
**Tags:** build-system, standard-library\
**Created:** [May 22, 2025, 1:25pm UTC](https://ziggit.dev/t/a-custom-build-zig-command-to-run-system-commands-and-see-their-output/10212 "2025-05-22T13:25:30Z")\
**Posts on this page:** 1\
**Showing post:** 8

<div class="post-metadata">

**Author:** ![asibahi](https://ziggit.dev/user_avatar/ziggit.dev/asibahi/32/5416_2.png) [@asibahi](https://ziggit.dev/u/asibahi)\
**Post date:** [May 29, 2025, 8:05pm UTC](https://ziggit.dev/t/a-custom-build-zig-command-to-run-system-commands-and-see-their-output/10212/8 "2025-05-29T20:05:57Z")

</div>

So I have been iterating on this and I hit a new snag.

This is the current code

```zig
// in `fn build`
    { // `zig build eye` command
        const eye_step = b.step("eye", "Eye test all the files in a given directory");

        if (b.option(std.Build.LazyPath, "folder", "Path to eye")) |lazy|
            try walk_tree(b, exe, eye_step, lazy)
        else
            eye_step.dependOn(&b.addFail("folder needed for eye").step);
    }

// later
fn walk_tree(
    b: *std.Build,
    exe: *std.Build.Step.Compile,
    eye_step: *std.Build.Step,
    lazy: std.Build.LazyPath,
) !void {
    const path = lazy.getPath3(b, null);
    const dir = try path.openDir("", .{ .iterate = true });
    var walker = dir.iterate();

    // const fail = b.option(bool, "fail", "failing tests") orelse false;

    var prev_run_cmd: ?*std.Build.Step.Run = null;
    while (try walker.next()) |entry| if (entry.kind == .file and
        std.mem.endsWith(u8, entry.name, ".c"))
    {
        const file = entry.name;

        const bat = b.addSystemCommand(&.{ "bat", file });
        bat.addArg("--paging=never");
        bat.setCwd(lazy);
        bat.stdio = .inherit;

        if (prev_run_cmd) |c|
            bat.step.dependOn(&c.step);

        const run_cmd = b.addRunArtifact(exe);
        // if (fail) run_cmd.expectExitCode(1);
        run_cmd.setCwd(lazy);
        run_cmd.addArg(file);
        run_cmd.addArgs(b.args orelse &.{});
        run_cmd.stdio = .inherit;

        run_cmd.step.dependOn(b.getInstallStep());
        run_cmd.step.dependOn(&bat.step);

        prev_run_cmd = run_cmd;
    };

    eye_step.dependOn(&prev_run_cmd.?.step);
}

```

Everything here works as intended. However , I am trying to add support for running this over tests that fail, i.e. my executable returns 1, and for whatever reason even with the two `fail` lines (that are committed out here), it still fails on the first `1` result. I even tried putting the `fail` option outside and passing it into the function but to no use.

Full file is in here in this branch [paella/build.zig at build-system-iter · asibahi/paella · GitHub](https://github.com/asibahi/paella/blob/build-system-iter/build.zig)

I am running it like so

```sh
zig build eye -Dfail -Dfolder=../writing-a-c-compiler-tests/tests/chapter_9/invalid_types -- --validate

```

---

_[View the full topic](https://ziggit.dev/t/a-custom-build-zig-command-to-run-system-commands-and-see-their-output/10212)._
