Arguments as single string literal

Hello! I’m trying to write a program where I can pass a string as argument and have it printed

$ ./myprogram hello world

hello world

I’m having trouble finding documentation for getting args as an single string literal. Is there a way to get the arguments passed to the program execution directly as a string literal?

First, you have to be aware that running ./myprogram heelo world would be passing 2 arguments, hello and world. I think this is a shell thing but definitely not a Zig thing. So you would have to run ./myprogram "hello world" to get them in a single string argument, or concatenate the separate args in your program. Here’s an example using std.process.argsWithAllocator:

var iter = try std.process.argsWithAllocator(allocator);
defer iter.deinit();

iter.skip(); // skip myprogram

while (iter.next()) |arg| {
    std.debug.print("{s}\n", .{arg});
}
2 Likes

More in general, note that command line arguments are generally passed as string from your terminal to the shell. String is the least common denominator in many cases… If your program expects a number as an argument, you will have to parse it from string to a numeric type. The common argument delimiter is the space character, so to pass arguments that contain a space, you’ll have to surround them by quotes, as @dude_the_builder already replied.

Besides, argument parsing is kind of its own discipline; there are some nice packages for Zig. For instance, clap or flags come to my mind right now, but there’s more out there.

Only on Windows: GetCommandLineA()

How can I concatenate each argument sent into a single string?

Note that this might not be what you want to do. On unix, there is no way to tell how many space characters are used between program arguments

I don’t know if that’s the way it’s done in programs like cowsay, I want to do something just like cowsay

$ cowsay hello world
 _____________ 
< hello world >
 ------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

try putting more spaces between the two arguments

You can use an ArrayList to combine multiple strings:

var list = std.ArrayList(u8).init(allocator);
defer list.deinit();

while (iter.next()) |arg| {
    list.appendSlice(arg);
    list.append(' ');
}
list.items.len -|= 1; // Remove the last space if needed

Of course as @prokoprandacek said, this won’t reproduce the exact input in all cases, but it should work fine for little toy applications like this.

1 Like

I think this works for me! Thanks everyone

Just before marking this as the solution, what is this -|= ? I’m not familiar with that syntax

It’s saturating subtraction. If the subtraction were to cause an overflow, it gets set to the minimum value instead, so

var foo: usize = 0;
foo -|= 1;
// foo is still zero

If you used regular subtraction, then you’d get an integer overflow in optimization modes with safety enabled:

thread 7160 panic: integer overflow
C:\Users\Ryan\Programming\Zig\tmp\saturating.zig:5:9: 0x841041 in test_0 (test.exe.obj)
    foo -= 1;
        ^
3 Likes

That’s cool! Thank you @squeek5023; Marking the @IntegratedQuantum previous message as the solution of this post.