Zig Tutorial #3

Robert Guiscard
2 min readMar 10, 2021

Zig is still a young language and lacks many libraries commonly used in other languages. Luckily we can take advantages of Unix pipe to help it. Unix pipe redirect the standard output to the standard input of the next program. Therefore, we only need to read standard input to get support of pipe.

Here is an example of supporting pipe in Zig:

const std = @import("std");
const fs = std.fs;
const mem = std.mem;
const String = @import("zig-string").String;pub fn main() anyerror!void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = &arena.allocator;
const stdin = std.io.getStdIn().reader();
const stat = try std.io.getStdIn().stat();
switch(stat.kind) {
std.fs.Dir.Entry.Kind.CharacterDevice => {
const fname = "spike.fasta";
var f = try fs.cwd().openFile(fname, fs.File.OpenFlags{ .read = true});
defer f.close();
try format_seq(allocator, &f.reader());
},
std.fs.Dir.Entry.Kind.NamedPipe => {
try format_seq(allocator, &stdin);
},
else => {
}
}
}
fn format_seq(allocator: *mem.Allocator, reader: *const std.io.Reader(std.fs.File,std.os.ReadError,std.fs.File.read)) !void {
// do something
while (true) {
if (reader.readUntilDelimiterAlloc(allocator, '\n', 1024)) |c| {
// process c
}
}
}

First, we obtain standard input by std.io.getStdIn(). But how do we know the program is used in pipe ? You can get the information from std.io.getStdIn().stat(). If the kind is CharacterDevice, it is not from pipe. If it is NamedPipe, it is from pipe.

We passed different kind of readers to our function by reference. Please note the type of parameters and return value (!void) in this case. If you use try in the function, you need to add ! for return value to properly handle error.

The compiled binary is under zip-cache/bin/. You can pipe to it like this:

echo "Hello World" | zip-cache/bin/zig_prog

If you write to standard output, you can also pipe from zig program to other Unix tool.

--

--